Arquivo de novembro, 2014

SAP – ABAP Unit – Testes Unitários – Abap

Publicado: 30 de novembro de 2014 em Abap

A maioria das metodologias disponíveis para o desenvolvimento de software e gerenciamento de projetos incluem como pratica básica essencial o desenvolvimento e execução de testes unitários para que um projeto de desenvolvimento possa passar para próxima fase.

Uma boa execução de um projeto bem elaborado em diversas metodologias utilizam ambientes e exigem que os testes unitários sejam executados no ambiente de desenvolvimento (DEV) utilizando uma ferramenta para este proposito e reexecutados por consultores  funcionais/testadores, na fase de testes unitários no ambiente real de qualidade (QAS) para que só então possam executar a fase de testes integrados antes de aprovarem e homologarem o software para utilização em um ambiente produtivo (PRD).

O teste unitário executado do ponto de vista do setor de qualidade (QAS) é feito validando todas as partes dos software, incluindo, design intuitivo, usabilidade, teclas de atalho, layouts, grafia, links e etc. É claro que existem algumas diferenças sutis entre metodologias, como um ou outro procedimento ou diferentes nomenclaturas mas no final todas possuem o mesmo proposito, um software de qualidade, livre de erros e dentro do orçamento inicial do projeto. Bem! No mundo real, não importa qual a metodologia escolhida, isto nem sempre é possível.

Contudo a SAP possui sua própria metodologia desenvolvida ao longo de 40 anos de experiência no mercado para software corporativo, e muitos destes anos como líder mundial em software empresarial, podemos afirmar que sua metodologia é comprovadamente eficiente e durante a evolução de seu desenvolvimento influenciou muitas outras metodologias de software existentes e vice versa, a nova versão da metodologia SAP também incorporou o DNA dos polêmicos métodos de desenvolvimento ágil e assim o ASAP 8 conta com duas aproximações da metodologia, o  Standard ASAP e Agile ASAP.

ASAP: http://scn.sap.com/community/asap-methodology

ABAP Unit

ABAP Unit é parte do ambiente de teste para programas ABAP. Unidade ABAP permite a implementação de testes de unidade e  execução manual e automática. Testes de unidade ABAP são métodos de classes ABAP especialmente designados. Os métodos de ensaio funcionam como scripts, com o qual o código a ser testado pode ser executado, e com a qual o resultado como em um ensaio pode ser avaliado. ABAP OO é conceitualmente parecido com Java e C++, deste modo os teste unitários ABAP são similares ao JUnit do Java. O ABAP Unit é adequado para desenvolvimento orientado a testes (TDD).

ABAP Unit: Abap Unit Overview

Executando Testes Unitários com  ABAP Unit

Os testes unitários ABAP podem ser escritos para classes ou para funções. Existe dois principais métodos de criar um teste unitário, eles são Global ou Local.

Global :

1 – Abra o Class Builder e crie uma classe chamada ZParticipante, com os seguintes atributos (você pode utilizar o código abaixo para se basear na criação da classe):

Classe - Atributos

Classe – Atributos

2 – Crie os seguintes métodos para a classe:

Classe - Métodos

Classe – Métodos

3 – Na barra de ferramentas clique em Source-Code Based e preencha os métodos para a classe ZParticipante de acordo com  a classe do código abaixo:

Classe - Implementação

Classe – Implementação

4 – Para criar uma classe de testes clique no menu Utilities->Test Class Generation e você será guiado pelo Wizard sobre como criar a classe de teste (Utilize a classe de teste encontrada abaixo para preencher o Wizard e implementar os métodos gerados).

  • Para acessar a classe de testes, no menu GO TO->Local Definitions/Implementation-> Local Test Classes.
  • Para testar os métodos clique no menu Class Source->Unit Test
Classe Teste - Wizard

Classe Teste – Wizard

Teste Unitário – ABAP Unit – Métodos

Um modo de testar um objeto é testando seus métodos Setters e retornando os métodos Getters como comparação, evitando assim erros de logica no objeto, além destes métodos você pode testar outros métodos do objeto como achar melhor:

1 – Caso não queira utilizar o método Global você pode testar classes locais diretamente de um programa ABAP, entre na transação SE38 e crie um programa chamado ZDAUNITESTE e utilize o código abaixo, compile e teste.

  • Para executar o teste unitário na classe, o procedimento é o mesmo do procedimento global, no menu Program->Test->Unit Test.
  • Para obter um erro no método substitua o valor de comparação no método ASSERT por um valor diferente do código abaixo:
Teste Unitário - Erros

Teste Unitário – Erros

2 – Corrija o código da classe de teste de acordo com o código abaixo e rode o teste novamente:

Teste Unitário - OK

Teste Unitário – OK

Exemplo:

Neste exemplo criamos uma simples classe com métodos Getter e Setter e uma classe de caso de teste para efetuar um teste unitário nos métodos criados.

Obs: O método utilizado para o testar o código abaixo é executado em um programa local, de modo local, caso queira testar classes globais com a classe de teste atrelada a classe testada, utilize os trechos das classes abaixo para criar as classes pelos Wizards do Class Builder como mostra as figuras acima.

ABAP

Classe – Participante

*&---------------------------------------------------------------------*
*& Report  ZDAUNITESTE
*&
*&---------------------------------------------------------------------*
*& Desenvolvimento Aberto
*& Testes unitários - ABAP
*&---------------------------------------------------------------------*

REPORT  ZDAUNITESTE.

* Cria classe Participante
class ZPARTICIPANTE definition.

  public section.

* Declara métodos Getter e Setter

    methods SETNOME importing  !PNOME type STRING .
    methods GETNOME returning value(RESULTADO) type STRING .
    methods SETIDADE importing !PIDADE type I .
    methods GETIDADE returning value(RESULTADO) type I .

  protected section.

* Declara atributos privados
  private section.

    data NOME type STRING .
    data IDADE type I .

ENDCLASS.

* Implementação da classe
CLASS ZPARTICIPANTE IMPLEMENTATION.

*  Metodos Getter e Setter

  METHOD GETIDADE.
    RESULTADO = me->IDADE.
    "Inverta o código acima: me->IDADE = RESULTADO
    "Você vai obter um erro de lógica
    "Passara pelo compilador ABAP
    "Mas não passara pelo teste Unitário
    "Deste modo você previne erros escritos
    "por desatenção ou desenvolvimento emergências
    "como nos Sprints em algumas metodologias

  ENDMETHOD.

  METHOD GETNOME.
    RESULTADO = me->NOME.
  ENDMETHOD.

  METHOD SETIDADE.
    me->IDADE = PIDADE.
  ENDMETHOD.

  METHOD SETNOME.
    me->NOME = PNOME.
  ENDMETHOD.
ENDCLASS.

* testa programa
START-OF-SELECTION.

* Testa Classe
  DATA: p1    TYPE REF TO ZPARTICIPANTE,
        nome  TYPE String,
        idade TYPE i.

* Istancia Objeto
  CREATE OBJECT P1.

* Métodos Setter
  p1->SETNOME( 'Joao da Silva' ).
  p1->SETIDADE( 20 ).

* Métodos Getter
  nome =  P1->GETNOME( ).
  idade = P1->GETIDADE( ).

* Imprime valores
  WRITE: / nome, idade.

* Classe de Teste Unitário.
* Na definição da classe de teste abaixo:
* "#AU Risk_Level Harmless não é um comentário
* e sim um decorador indicando o nível risco do teste
* sem este decorador a classe não testará os métodos.

CLASS ZPARTICIPANTE_TEST DEFINITION FOR TESTING."#AU Risk_Level Harmless

  PUBLIC SECTION.

    METHODS:
      SETNOME FOR TESTING,
      SETIDADE FOR TESTING.

ENDCLASS.

CLASS ZPARTICIPANTE_TEST IMPLEMENTATION.

* Teste unitario para metodos Getter e Setter
  METHOD SETNOME.

    DATA p1 TYPE REF TO ZPARTICIPANTE.
    CREATE OBJECT p1.

    p1->SETNOME('Nome').
    cl_aunit_assert=>ASSERT_EQUALS(
      exporting
        EXP                  =     'Nome'          " Data Object with Expected Type
        ACT                  =     p1->GETNOME( )  " Data Object with Current Value

    ).
  ENDMETHOD.

  METHOD SETIDADE.
    DATA p2 TYPE REF TO ZPARTICIPANTE.
    CREATE OBJECT p2.

    p2->SETIDADE( 20 ).
    cl_aunit_assert=>ASSERT_EQUALS(
      exporting
        EXP                  =     20          " Data Object with Expected Type
        ACT                  =     p2->GETIDADE( )  " Data Object with Current Value

    ).
  ENDMETHOD.

ENDCLASS.

PyCharm – Testes Unitários – Python

Publicado: 28 de novembro de 2014 em Python

A maioria das metodologias disponíveis para o desenvolvimento de software e gerenciamento de projetos incluem como pratica básica essencial o desenvolvimento e execução de testes unitários para que um projeto de desenvolvimento possa passar para próxima fase.

Uma boa execução de um projeto bem elaborado em diversas metodologias utilizam ambientes e exigem que os testes unitários sejam executados no ambiente de desenvolvimento (DEV) utilizando uma ferramenta para este proposito e reexecutados por consultores  funcionais/testadores, na fase de testes unitários no ambiente real de qualidade (QAS) para que só então possam executar a fase de testes integrados antes de aprovarem e homologarem o software para utilização em um ambiente produtivo (PRD).

O teste unitário executado do ponto de vista do setor de qualidade (QAS) é feito validando todas as partes dos software, incluindo, design intuitivo, usabilidade, teclas de atalho, layouts, grafia, links e etc. É claro que existem algumas diferenças sutis entre metodologias, como um ou outro procedimento ou diferentes nomenclaturas mas no final todas possuem o mesmo proposito, um software de qualidade, livre de erros e dentro do orçamento inicial do projeto. Bem! No mundo real, não importa qual a metodologia escolhida, isto nem sempre é possível.

PyCharm Community IDE

PyCharm é um ambiente profissional de desenvolvimento integrado (IDE) utilizado para a programação em Python. Ele fornece uma análise de código, depurador gráfico, testador unidade integrada, integração VCS/DVCS e apoia o desenvolvimento web com Django. Muitos desenvolvedores da comunidade Python elegeram o PyCharm como a melhor IDE para desenvolvimento Python, a IDE pode ser utilizada na versão comunitária ou na versão paga.

PyCharm: http://www.jetbrains.com/pycharm/

PyUnit – Unit Test Framework

O framework de testes unitários para Python, por vezes referido como PyUnit é uma versão da linguagem Python do JUnit. O JUnit é, por sua vez, uma versão Java do framework de testes Smalltalk, o JUnit é muito conhecido e utilizado no mudo Java também proliferou para outras linguagem de programação como entre outras, para C#.

PyUnit: https://docs.python.org/2/library/unittest.html

Executando Testes Unitários no PyCharm

1 – Crie um novo projeto Python chamado DAPyTeste, crie um novo arquivo Python chamado Participante e utilize o código encontrado logo abaixo. Na declaração da classe Participante clique com o botão direito e escolha Go To->Test:

Cria Classe de Teste

Cria Classe de Teste

2 – Para criar o teste escolha apenas os métodos Setters:

Métodos Setters

Métodos Setters

3 – Complete os métodos com respectivo código da classe de teste encontrado logo abaixo, utilize os comentários no código para saber mais sobre os teste unitários.

  • Para efetuar um teste com erros, modifique os valores alimentados nos métodos de teste.
  • Para rodar o teste na barra de ferramentas, selecione Unittests in DAPyTeste e clique em Run:
Erros

Erros

4 – Retorne os valores dos métodos como no código abaixo e execute o teste novamente:

Testes bem sucedidos

Testes bem sucedidos

 

Exemplo:

Neste exemplo criamos uma simples classe com métodos Getter e Setter e uma classe de caso de teste para efetuar um teste unitário nos métodos criados.

Python

Classe – Participante

# coding=utf-8
# Desenvolvimento Aberto
# Participante.py

__author__ = 'Desenvolvimento Aberto'

class Participante():

     # Define atributos privados
     def __init__(self):
         self.__nome = None
         self.__idade = None

     # Define métodos Getter e Setter
     def getNome(self):
         return self.__nome

     def setNome(self, nome):
         self.__nome = nome
         #Inverta o código acima: nome = self.nome
         #Você vai obter um erro de lógica
         #Passara pelo interpretador Python
         #Mas não passara pelo teste Unitário
         #Deste modo você previne erros escritos
         #por desatenção ou desenvolvimento emergências
         #como nos Sprints em algumas metodologias

     def getIdade(self):
         return self.__idade

     def setIdade(self, idade):
         self.__idade = idade

     # Você também pode optar por propriedades
     # Aos métodos Getter e Setter
     # Segue exemplo propriedade Nome:
     @property
     def Nome(self):
         return self.__nome

     @Nome.setter
     def Nome(self, value):
         self.__nome = value

# Cria Instancia da Classe
participante = Participante()

#Alimenta valores
participante.setNome("Joao da Silva")
participante.setIdade(20)

# Imprime dados
print participante.getNome()
print participante.getIdade()

PyUnit Test Case – ParticipanteTeste

# coding=utf-8
# Desenvolvimento Aberto
# TestParticipante.py

from unittest import TestCase
from Participante import Participante

__author__ = 'Desenvolvimento Aberto'

class TestParticipante(TestCase):

    # Define Métodos de Testes

    def test_setNome(self):
        # Testa métodos Getter e Setter
        p1 = Participante()
        p1.setNome("Nome")
        self.assertEqual("Nome", p1.getNome())

    def test_setIdade(self):
        # Testa métodos Getter e Setter
        p2 = Participante()
        p2.setIdade(20)
        self.assertEqual(20, p2.getIdade())

A maioria das metodologias disponíveis para o desenvolvimento de software e gerenciamento de projetos incluem como pratica básica essencial o desenvolvimento e execução de testes unitários para que um projeto de desenvolvimento possa passar para próxima fase.

Uma boa execução de um projeto bem elaborado em diversas metodologias utilizam ambientes e exigem que os testes unitários sejam executados no ambiente de desenvolvimento (DEV) utilizando uma ferramenta para este proposito e reexecutados por consultores  funcionais/testadores, na fase de testes unitários no ambiente real de qualidade (QAS) para que só então possam executar a fase de testes integrados antes de aprovarem e homologarem o software para utilização em um ambiente produtivo (PRD).

O teste unitário executado do ponto de vista do setor de qualidade (QAS) é feito validando todas as partes dos software, incluindo, design intuitivo, usabilidade, teclas de atalho, layouts, grafia, links e etc. É claro que existem algumas diferenças sutis entre metodologias, como um ou outro procedimento ou diferentes nomenclaturas mas no final todas possuem o mesmo proposito, um software de qualidade, livre de erros e dentro do orçamento inicial do projeto. Bem! No mundo real, não importa qual a metodologia escolhida, isto nem sempre é possível.

Microsoft Unit Test Framework for Managed Code

O framework de testes de unidade da Microsoft para código gerenciado é instalado com o Visual Studio e fornece um framework para testar o código .NET. As ferramentas de teste de unidade do Visual Studio foram desenvolvidas para oferecer suporte a desenvolvedores e equipes que incorporam testes unitários em suas práticas de desenvolvimento de software.  Testes de unidade proporcionam aos desenvolvedores e testadores uma maneira rápida para procurar erros de lógica nos métodos de classes em soluções .NET.

Unit Test Framework: http://msdn.microsoft.com/pt-br/library/dd264975.aspx

Executando Testes Unitários no Visual Studio

1 – Crie uma solução C# para o console chamada DATesteUnitario, renomeie o arquivo da classe gerado automaticamente de acordo com a classe do código Participante encontrado logo abaixo. Crie um novo projeto C# para teste chamado DATesteUnitarioTest nesta mesma solução:

Projeto - Test - C#

Projeto – Test – C#

2 – No Solution Explorer no projeto DATesteUnitarioTest adicione uma referencia ao projeto DATesteUnitario:

Adicionar Referencia

Adicionar Referencia

3 – Renomeie a classe criada automaticamente para o projeto de testes para ParticipanteTeste e utilize os métodos do código abaixo, atente-se aos comentários do código fonte para saber mais detalhes sobre os padrões de teste nos objetos C# no Visual Studio.

  • Para efetuar um teste com erros, modifique os valores alimentados na propriedade nome e idade nos métodos de teste.
  • Para rodar o teste, clique no menu Test e escolha a opção All Tests, o Visual Studio irá abrir uma janela chamada Test Explorer onde será exibido o resultado do teste de seus métodos:
Testes com Erros

Testes com Erros

4 – Retorne os valores das propriedades como no código abaixo, selecione os dois métodos com erros na janela Test Explorer e com o botão direito escolha a opção Run Selected Tests:

Testes bem Sucedidos

Testes bem Sucedidos

 

Exemplo:

Neste exemplo criamos uma simples classe com propriedades Get e Set e uma classe de caso de teste para efetuar um teste unitário nos métodos criados.

C#

Classe – Participante

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DATesteUnitario
{
    public class Participante
    {
        // Atributos da classe
        private string nome;
        private int idade;

        // Propriedades
        public string Nome {
            get
            {
                return nome;
            }
            set
            {
                 nome = value;
            }
        }

        public int Idade {
            get
            {
                return idade;
            }
            set
            {
               idade = value;
               // Troque a linha acima por: value = idade;
               // funciona na sintaxe mas não passa no teste unitário
               // pois é erro básico de logica e pode ser escrito em
               // um momento de desatenção.
            }
        }

        static void Main(string[] args)
        {
            // Testa classe
            // Dumb Code - Sem efeito para o teste
            Participante participante = new Participante();

            participante.Idade = 20;
            participante.Nome = "João da Silva";

            Console.ReadKey();
        }

    }
}

JUnit Test Case – ParticipanteTeste

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using DATesteUnitario; // Namespace do projeto a ser testado

namespace DATesteUnitarioTest
{
    [TestClass]
    public class ParticipanteTeste
    {
        /*          
         * Você pode optar por utilizar métodos Getter e Setter como Java (Bean).
         * Entretanto na linguagem C# métodos Getter e Setter são substituidos por
         * propriedades semelhantes a linguagem de programação Object Pascal (Delphi).
         *
         * O conceito de testes unitários é utilizado sempre através de métodos Setter (Voids)
         * pois o mesmo já testa o método de retorno Getter no momento da comparação.
         * Os métodos testados são os Construtores da classe, métodos Setter ou
         * outros métodos da classes de sua preferencia.
         *
         * O Caso de teste unitário do Projeto de Test C# é bem parecido com o JUnit para Java
         * utilizando o conceito de Assert e possui os seguintes requisitos:
         *
         * O método deve ser decorado com o atributo [TestMethod].
         * O método deve retornar void.
         * O método não pode ter parâmetros.
         *
         * Como testar um básico Pattern de Objeto C#
         * baseados em Get e Set (propriedades em C#)
         * utilizando voids?
         *
         * Podemos utilizar métodos semelhantes ao JUnit do Java, mas atente-se
         * pois diferentemente do JUnit a classe de teste não está fisicamente ligada
         * a classe a ser testada e utiliza uma void padrão.
         *
         * Método de teste padrão:

        [TestMethod]
        public void TestMethod1()
        {
        }

        */

        //Testando propriedades
         [TestMethod]
        public void Nome()
        {
             // Testa propriedade Nome
             Participante p1 = new Participante();
             p1.Nome = "Nome";
             Assert.AreEqual("Nome", p1.Nome);

        }

        [TestMethod]
        public void Idade()
         {
             // Testa propriedade Idade
             Participante p2 = new Participante();
             p2.Idade = 20;
             Assert.AreEqual(20, p2.Idade);
         }

    }
}

JUnit – Testes Unitários – Java

Publicado: 27 de novembro de 2014 em Java

A maioria das metodologias disponíveis para o desenvolvimento de software e gerenciamento de projetos incluem como pratica básica essencial o desenvolvimento e execução de testes unitários para que um projeto de desenvolvimento possa passar para próxima fase.

Uma boa execução de um projeto bem elaborado em diversas metodologias utilizam ambientes e exigem que os testes unitários sejam executados no ambiente de desenvolvimento (DEV) utilizando uma ferramenta para este proposito e reexecutados por consultores funcionais/testadores, na fase de testes unitários no ambiente real de qualidade (QAS) para que só então possam executar a fase de testes integrados antes de aprovarem e homologarem o software para utilização em um ambiente produtivo (PRD).

O teste unitário executado do ponto de vista do setor de qualidade (QAS) é feito validando todas as partes dos software, incluindo, design intuitivo, usabilidade, teclas de atalho, layouts, grafia, links e etc. É claro que existem algumas diferenças sutis entre metodologias, como um ou outro procedimento ou diferentes nomenclaturas mas no final todas possuem o mesmo proposito, um software de qualidade, livre de erros e dentro do orçamento inicial do projeto. Bem! No mundo real, não importa qual a metodologia escolhida, isto nem sempre é possível.

JUnit

O JUnit é um framework de código aberto, com suporte à criação de testes unitários para linguagem de programação Java. Esse framework facilita a criação de código para a automação de testes com apresentação dos resultados. Com ele, pode ser verificado se cada método de uma classe funciona da forma esperada, exibindo possíveis erros ou falhas.

JUnit: http://junit.org/

Executando Testes Unitários no Eclipse

1 – Crie um projeto Java SE no Eclipse e crie uma classe chamada de Participante dentro de um pacote chamado org.desenvolvimento.aberto. Utilize o código abaixo para preencher o código da classe que acabou de criar. Crie uma nova pasta chamada test para código escolhendo a opção: File->New->Source Foulder:

Source Folder

Source Folder

2 – Após criar a pasta de teste crie também o mesmo pacote para a pasta de teste:

Package

Package

3 – Clique com o botão direito em cima do pacote que acabou de criar e escolha a opção: New->JUnit Test Case. Defina o nome da classe como ParticipanteTeste e na opção Class Under Test escolha a classe Participante e clique em próximo:

JUnit Test Case

JUnit Test Case

4 – Para escolher os métodos da classe para teste sempre escolha somente os construtores da classe (caso haja construtores Overload) e os métodos Setters, não escolheremos os métodos Getters pois os utilizaremos para testar os métodos Setters no caso de teste:

Métodos para teste

Métodos para teste

5 – Após clicar em Finish, quando você utiliza o JUnit pela primeira vez você precisa adicionar a biblioteca do Framework JUnit no Build Path do Eclipse, você pode fazer isto de vários modos, o mais fácil é clicando em OK na próxima janela:

JUnit - Build Path

JUnit – Build Path

6 – Uma classe de testes foi criada para você com métodos ainda não implementados, no qual precisamos implementar para que possamos executar com sucesso os testes unitários. Na barra de ferramentas escolha Run As e clique na opção: JUnit Test:

Compilar Classe de Teste

Compilar Classe de Teste

7 – Como ainda não implementamos os métodos para garantir que nossa classe que está sobre testes tenha sucesso, vamos obter um erro na aba JUnit que aparecerá do lado esquerdo ao lado da aba de exploração do projeto:

JUnit - Erro

JUnit – Erro

8 – Para implementar os métodos de teste na classe de teste, precisamos instanciar o objeto da classe que será testada, alimentar um valor em seu método Setter e depois comparar o valor alimentado com o valor retornado pelo método Getter, deste modo confirmamos que todos os métodos do objeto sejam testado. Utilize o código abaixo para implementar sua classe de testes e compile novamente a classe de teste:

Teste Unitário - OK

Teste Unitário – OK

Exemplo:

Neste exemplo criamos uma simples classe com métodos Getters e Setters e uma classe de caso de teste para efetuar um teste unitário nos métodos criados.

Java

Classe – Participante

package org.desenvolvimento.aberto;

public class Participante {

	// Declara atributos da classe
	private String nome;
	private int idade;

	// Declara métodos Getter e Setter da classe
	public String getNome()
	{
		return nome;
	}

	public void setNome(String nome)
	{
		this.nome = nome;

          // Troque a linha acima por: nome = this.nome;
          // funciona na sintaxe mas não passa no teste unitário
          // pois é erro básico de logica e pode ser escrito em
          // um momento de desatenção.

	}

	public int getIdade()
	{
		return idade;
	}

	public void setIdade(int idade)
	{
		this.idade = idade;
	}

}

JUnit Test Case – ParticipanteTeste

package org.desenvolvimento.aberto;

import static org.junit.Assert.*;

import org.junit.Test;

public class ParticipanteTeste {

	@Test
	public void testSetNome()
	{
		// Implementa método de teste unitário: Nome
		Participante p1 = new Participante();
		p1.setNome("Jose");
		assertEquals("Jose", p1.getNome());
	}

	@Test
	public void testSetIdade()
	{
		// Implementa método de teste unitário: Idade
		Participante p2 = new Participante();
		p2.setIdade(20);
		assertEquals(20, p2.getIdade());
	}

}

Session – Login – Logout – Timeout – Java

Publicado: 26 de novembro de 2014 em Java

Tarefas de gerenciamento de sessão típicas incluem manter o controle de quais aplicativos estão abertos e documentar cada aplicativo que abriu, para que o mesmo estado possa ser restaurado quando o usuário sair e entrar novamente mais tarde. Você também pode utilizar a Session para criar áreas restritas de um website que podem ser acessadas pela sessão de um usuário, você também pode definir um tempo para que esta sessão fique ativa no navegador do usuário autenticado.

Para um site, gerenciamento de sessão pode envolver e exigir que o usuário reinicie sessão se a sessão expirou ou seja, se um certo limite de tempo passou sem a atividade do usuário. A sessão também é usada para armazenar informações no lado do servidor entre solicitações HTTP. Este tipo de conceito básico é o principio do esquema de autenticação utilizado por vários websites, entretanto a partir deste esquema básico pode-se criar métodos mais eficientes para utilizar este conceito.

Criando uma Sessão

GetSession

Retorna a sessão atual associado a este pedido, ou se o pedido não tem uma sessão, cria uma.

https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletRequest.html#getSession()

SetAttribute

Vincula um objeto para esta sessão, usando um nome especificado. Se um objeto do mesmo nome já está ligado à sessão, o objeto é substituído.

https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSession.html

Utilizando Sessions – Login, Logout e Timeout

1 – Crie um projeto web dinâmico e os Servlets chamados Autenticar, SairAreaComunitaria, utilize o código abaixo para cada respectivo arquivo e rode a aplicação. Você pode tentar chamar a pagina AreaComunitaria sem utilizar o usuário e senha, digitando o nome do Servlet na url do navegador e constatará que não pode acessar a pagina devido a inexistência da sessão para seu usuário. Efetue o Login para criar a sessão:

Session - Login

Session – Login

2 – Assim que efetuar o login você será direcionado a área comunitária podendo então acessar a pagina da comunidade, caso clique no link sair, a sessão será invalidada e você será redirecionado para a tela de login:

Session - Área Comunitária

Session – Área Comunitária

3 – Ao incluir as tags de configuração da sessão no arquivo web.xml você pode definir o tempo em minutos que deseja que sessão seja valida. Use o código do arquivo xml abaixo para fazer com que a sessão dure 1 minuto, efetue o login, aguarde um minuto e atualize a pagina, com a sessão expirada você será redirecionado novamente para a pagina de login:

Session - Timeout

Session – Timeout

Exemplo:

Neste exemplo criamos uma pagina de login com a funcionalidade de autenticar em uma pagina somente para membros da comunidade e utilizamos o recurso de timeout da sessão para que ela expire assim que o usuário estiver autenticado por 1 minuto.

Obs: usuário: DevAberto e a senha: 1234

Java

Servlet – Autenticar

package org.desenvolvimento.aberto;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/Autenticar")
public class Autenticar extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public Autenticar() {
		super();
	}

	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		// Mostra pagina HTML
		response.setContentType("text/html");

		PrintWriter html = response.getWriter();

		html.println("<html>");
		html.println("<body>");
		html.println("<h1>Desenvolvimento Aberto</h1>");
		html.println("<h2>Login: </h2>");

		// Formulário processa este mesmo Servlet e o método DoPost
		html.println("<form action='Autenticar' method='post'>");

		html.println("Nome  : <input type='text' name='nome' size ='40' /> <br>");
		html.println("Senha : <input type='password' name='senha' size ='40' /> ");
		html.println("<input type='submit' name='login' value='Login'/> <br>");

		html.println("</form>");
		html.println("</body>");
		html.println("</html>");

	}

	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		String usuario = request.getParameter("nome");
		String senha = request.getParameter("senha");

		// Verifica usuario e senha
		// provavelmente você utilizará um banco de dados
		// Neste exemplo utilizaremos valores fixos

		if (usuario.equals("DevAberto") && senha.equals("1234")) {
			request.getSession().setAttribute("usuario", usuario);
			response.sendRedirect("AreaComunidade");
		} 
		else {
			response.sendRedirect("Autenticar");
		}

	}

}

Servlet – Sair

package org.desenvolvimento.aberto;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/Sair")
public class Sair extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public Sair() {
		super();
	}

	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		// Invalida sessão e redireciona para login
		request.getSession().invalidate();
		response.sendRedirect("Autenticar");
	}

	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
	}

}

Servlet – AreaComunitaria

package org.desenvolvimento.aberto;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/AreaComunidade")
public class AreaComunidade extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public AreaComunidade() {
		super();
	}

	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		// Mostra pagina HTML
		response.setContentType("text/html");

		PrintWriter html = response.getWriter();

		String usuario = (String) request.getSession().getAttribute("usuario");

		if (usuario != null) {
			html.println("<html>");
			html.println("<body>");
			html.println("<h1>Desenvolvimento Aberto</h1>");
			html.println("<h2>Area da Comunidade - Java  </h2>");
			html.println("<h3>Bem-vindo: " + usuario + "</h3>");
			html.println("<p><a href='Sair'>Sair</a></p>");
			html.println("</body>");
			html.println("</html>");
		}
		else
		{
			response.sendRedirect("Autenticar");
		}
	}

	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
	}

}

Config – web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	id="WebApp_ID" version="3.1">
	<display-name>DACliente</display-name>
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>index.htm</welcome-file>
		<welcome-file>index.jsp</welcome-file>
		<welcome-file>default.html</welcome-file>
		<welcome-file>default.htm</welcome-file>
		<welcome-file>default.jsp</welcome-file>
	</welcome-file-list>
	<session-config>
		<session-timeout>1</session-timeout>
	</session-config>
</web-app>

JSP – Cookie e Session Attribute – Java

Publicado: 25 de novembro de 2014 em Java

Em ciência da computação, uma sessão é um intercâmbio semipermanente de informações interativas, também conhecido como um diálogo, uma conversa ou uma reunião, entre dois ou mais dispositivos de comunicação, ou entre um computador e usuário. Uma sessão HTTP é uma sequência de transações de rede de requisição-resposta e se dá da seguinte forma, um cliente HTTP inicia uma requisição estabelecendo uma conexão Transmission Control Protocol (TCP) para uma porta particular de um servidor. Um servidor HTTP ouvindo naquela porta espera por uma mensagem de requisição de cliente. Recebendo a requisição, o servidor retorna uma linha de estado, como “HTTP/1.1 200 OK“, e uma mensagem particular própria. O corpo desta mensagem normalmente é o recurso solicitado, apesar de uma mensagem de erro ou outra informação também poder ser retornada.

Um identificador de sessão, ID da sessão ou token de sessão é um pedaço de dados que é usado em comunicações de rede  para identificar uma sessão, uma série de trocas de mensagens relacionadas. As sessões são identificadas por único identificador (ID) no qual é associado aos dados criados no servidor, este identificador é gerado aleatoriamente e de difícil falsificação. O rastreamento de sessões é efetuado por padrão através de cookies.

HTTP Session: https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSession.html

Utilizando Cookies e Sessions

1 – Crie um novo projeto web dinâmico e crie um novo Servlet chamado MeuCookie e MinhaSessao, utilize o código abaixo e rode sua aplicação, enquanto a aplicação está rodando na instancia do Tomcat do Eclipse, abra o seu navegador padrão e cole a url do navegador interno do Eclipse em seu browser, neste exemplo utilizamos o Firefox e logo após a pagina ser exibida digite seu nome no campo de texto e clique no botão da pagina:

Cria Cookie

Cookie

2 – Assim que o método do botão for executado, um cookie e um atributo para a sessão serão criados, a pagina seguinte não lerá o nome guardado no cookie e sim no atributo da sessão criada no servidor através de seu identificador, você pode abrir outras instancias do navegador e copiar e colar a url para que você brinque com a sessão.

Sessão

Sessão

3 – Para ver o cookie e a sessão criada no seu navegador, abra Opções no menu do Firefox e escolha a aba privacidade:

Firefox - Opções -  Privacidade

Firefox – Opções – Privacidade

4 – Clique no link excluir cookies em particular e digite no campo de busca, localhost. Selecione o cookie pelo seu nome e você pode ver os dados gravados no mesmo.

Firefox - Cookie

Firefox – Cookie

5 – Selecione a opção JSESSIONID e você verá o ID da sessão em você está conectado, assim que você fechar o browser o cookie e a sessão serão excluídos.

Session ID

Session ID

Exemplo:

Neste exemplo criamos um cookie e definimos um atributo para a sessão com o valor do cookie e logo recuperamos o atributo da sessão para que possamos exibir o valor gravado no cookie.

Java

Servlet – MeuCookie

package org.desenvolvimento.aberto;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/MeuCookie")
public class MeuCookie extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public MeuCookie() {
		super();
	}

	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		// Mostra pagina HTML
		response.setContentType("text/html");

		PrintWriter html = response.getWriter();

		html.println("<html>");
		html.println("<body>");
		html.println("<h1>Desenvolvimento Aberto</h1>");
		html.println("<h2>Cookies - Memoriza Dados</h2>");

		// Formulário processa este mesmo Servlet e o método DoPost
		html.println("<form action='MeuCookie' method='post'>");

		// Manipula cookie
		String nome = getDaCookieNome(request);
		if (nome != null)
			html.println("Nome: " + nome + " <br> ");
		else {
			html.println("Nome: <input type='text' name='nome' size ='55' /> ");
			html.println("<input type='submit' name='adiciona' value='Adicionar'/> <br>");
		}

		html.println("<a href='MinhaSessao'>testar Sessão</a>");
		html.println("</form>");
		html.println("</body>");
		html.println("</html>");
	}

	private String getDaCookieNome(HttpServletRequest request) {

		// Recupera cookie
		for (Cookie cookie : request.getCookies())
			if (cookie.getName().equals("DAname3"))
				return cookie.getValue();

		return null;
	}

	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		// Recupera cookie
		String nome = getDaCookieNome(request);

		if (nome == null) {

			// Recupera parâmetro
			nome = request.getParameter("nome");

			// Define sessão
			request.getSession().setAttribute("DAname3", nome);

			// Cria Cookie
			Cookie cookie = new Cookie("DAname3", nome);

			// Redireciona página
			response.addCookie(cookie);

			// Redireciona página
			response.sendRedirect("MinhaSessao");
		}
	}
}

 

Servlet – MinhaSessao

package org.desenvolvimento.aberto;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/MinhaSessao")
public class MinhaSessao extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public MinhaSessao() {
		super();
	}

	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		// Mostra pagina HTML
		response.setContentType("text/html");

		PrintWriter html = response.getWriter();

		html.println("<html>");
		html.println("<body>");
		html.println("<h1>Desenvolvimento Aberto</h1>");
		html.println("<h2>Cookies Sessão- Memoriza Dados Por Sessão</h2>");

		// Recupera sessão
		String nome = (String) request.getSession().getAttribute("DAname3");

		if (nome != null)
			html.println("Nome: " + nome + " <br> ");
		else {
			html.println("Nome: Não identificado  <br> ");
		}

		html.println("</form>");
		html.println("</body>");
		html.println("</html>");
	}

	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
	}

}

JSP – Cookies – Java

Publicado: 24 de novembro de 2014 em Java

Um cookie é um pequeno pedaço de dados enviado de a partir de um website e armazenado em um arquivo de texto criado no computador do usuário enquanto ele está navegando em um site. Cada vez que o usuário carrega o website, o navegador envia o cookie de volta ao servidor para notificar o site da atividade prévia do usuário. Os cookies foram projetados para serem um mecanismo confiável para sites recordarem informações de estado ou para registrar a atividade de navegação do usuário.

Cookie é um assunto que trouxe e ainda levanta muita controvérsia no universo da computação para web, devido a questões de segurança quanto a manipular informações no computador local, fazem com que todos os tipos de usuários se preocupe com as informações utilizadas em websites principalmente se utilizar computadores que são compartilhados com varias pessoas como em lan houses ou outros.

Java possui a classe Cookies que permite que o desenvolvedor manipule cookies em suas aplicações web seguindo as especificações do RFC 2109, está classe representa os valores de um cookie HTTP.

Cookies: https://docs.oracle.com/javaee/7/api/javax/ws/rs/core/Cookie.html

Utilizando Cookies

1 – Crie um novo projeto web dinâmico e crie um novo Servlet chamado MeuCookie, utilize o código abaixo e rode sua aplicação, digite seu nome no campo de texto e clique no botão:

Cookie - Java

Cookie – Java

2 – Assim que o botão recebe o evento de clique o método doPost cria o cookie no computador local guardando em seu arquivo o nome do usuário, a pagina é recarregada e o cookie é lido automaticamente, toda vez que você tentar recarregar esta página o cookie será lido e o nome guardado automaticamente preenchido:

Cookie - Nome

Cookie – Nome

Exemplo:

Neste exemplo criamos uma página que grava e lê um cookie no computador local.

Java

package org.desenvolvimento.aberto;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/MeuCookie")
public class MeuCookie extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public MeuCookie() {
		super();
	}

	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		// Mostra pagina HTML
		response.setContentType("text/html");

		PrintWriter html = response.getWriter();

		html.println("<html>");
		html.println("<body>");
		html.println("<h1>Desenvolvimento Aberto</h1>");
		html.println("<h2>Cookies - Memoriza Dados</h2>");

		// Formulário processa este mesmo Servlet e o método DoPost
		html.println("<form action='MeuCookie' method='post'>");

		// Manipula cookie
		String nome = getDaCookieNome(request);
		if (nome != null)
			html.println("Nome: " + nome + " <br> ");
		else {
			html.println("Nome: <input type='text' name='nome' size ='55' /> ");
			html.println("<input type='submit' name='adiciona' value='Adicionar'/> <br>");
		}

		html.println("</form>");
		html.println("</body>");
		html.println("</html>");
	}

	private String getDaCookieNome(HttpServletRequest request) {
		
		// Recupera cookie
		for (Cookie cookie : request.getCookies())
			if (cookie.getName().equals("DAname1"))
				return cookie.getValue();

		return null;
	}

	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		String nome = getDaCookieNome(request);
		if (nome == null) {

			nome = request.getParameter("nome");

			// Cria Cookie
			Cookie cookie = new Cookie("DAname1", nome);
			
			// Redireciona página
			response.addCookie(cookie);

			// Redireciona página
			response.sendRedirect("MeuCookie");
		}
	}

}

JSP – HTTP – Responses – Status Code – Java

Publicado: 20 de novembro de 2014 em Java

A cada solicitação do protocolo HTTP o servidor indica uma resposta provisória, consistindo somente da linha de status e cabeçalhos opcionaisencerrado por uma linha vazia. As respostas podem conter por exemplo erros de HTTP que são enviados para o navegador da Web pelo servidor se um problema for encontrado durante a tentativa de exibir uma página da Web. Se a página da Web não for exibida, o servidor exibirá a página de erro real enviada pelo site ou uma mensagem de erro amigável.

As vezes é útil criar uma pagina customizada para as paginas geradas automaticamente pelo servidor pois o mesmo pode mostrar nestas paginas informações que não queremos que o usuário remoto tenha conhecimento, além das boas praticas e uma mensagem esteticamente amigável, ainda temos entre os motivos, a segurança.

Para uma lista completa de todos os códigos de resposta enviados pelo servidor utilize o link abaixo:

Response Status Code: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

Customizando uma Página de Erro

1 – Crie um projeto Java Web dinâmico, crie uma nova pagina chamada de index.jsp, utilize o código abaixo para o XHTML da pagina e rode a aplicação:

Index.jsp

Index.jsp

2 – Clique no link “Java” para que você obtenha a pagina de erro com a resposta gerada pelo servidor:

Response - Erro - 404

Response – Erro – 404

3 – Para substituir a pagina automática por uma pagina mais amigável precisamos capturar a resposta do servidor e exibir uma pagina com informações customizadas, entretanto não queremos que o usuário tenha acesso a esta pagina via o navegador, então precisamos criar uma pagina chamada de 404.jsp na pasta chamada WEB-INF e alterar o web.xml localizado na mesma pasta, redirecionando a resposta 404 para a pagina 404.jsp. Crie a pagina 404.jsp e altere o arquivo web.xml utilizando os respectivos códigos abaixo, em seguida rode a aplicação e com ela rodando copie a URL e cole no seu navegador:

Aplicação - Firefox

Aplicação – Firefox

4 – Clique novamente na opção “Java” e sua pagina customizada será exibida sem que nenhuma informação do servidor e de sua aplicação seja apresentada para o usuário remoto:

Response 404 - Customizada

Response 404 – Customizada

Exemplo:

Neste exemplo utilizamos a resposta do servidor para substituir a mensagem de erro 404 por uma mensagem exibida em uma pagina customizada.

Java

index.jsp

<?xml version="1.0" encoding="ISO-8859-1" ?>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Desenvolvimento Aberto - HTTP Respostas</title>
<style>
#header {
	background-color: Black;
	color: white;
	text-align: center;
	padding: 5px;
}

#nav {
	line-height: 30px;
	background-color: #eeeeee;
	height: 400px;
	width: 100px;
	float: left;
	padding: 5px;
}

#section {
	width: 450px;
	float: left;
	padding: 10px;
}

#footer {
	background-color: Black;
	color: white;
	clear: both;
	text-align: center;
	padding: 5px;
}
</style>

</head>
<body>
	<div id="header">
		<h1>Desenvolvimento Aberto</h1>
	</div>

	<div id="nav">

		<!-- HTTP Response: 

	     Este link referencia uma página que não existe,
	     deste modo o servidor nos enviará um erro 404  -->
		<p>
			<a href='nao-existe.jsp'>Java</a>
		</p>
		<p>JSP</p>
		<p>JavaBeans</p>
		<p>Servlet</p>

	</div>

	<div id="section">
		<h2>Desenvolvimento Aberto</h2>
		<p>Desenvolvimento Aberto é uma organização voltada para o
			aprendizado e discussão de técnicas de desenvolvimento focado em
			algumas linguagens de programação sendo parcialmente/totalmente
			abertas ou com licenças gratuitas para desenvolvedores de cada uma de
			suas respectivas marcas registradas.</p>
		<p>Desenvolvimento Aberto foi escrito e desenvolve utilizando
			ferramentas gratuitas disponibilizadas pelas melhores empresas de
			software da atualidade, incluindo a própria hospedagem e design deste
			site, sendo assim, também proporciona conteúdo gratuito, isso quer
			dizer que você não paga nada para aprender e utilizar as tecnologias
			de ponta que podem ser manuseadas através das linguagens de
			programação mais requisitadas pelas empresas no mercado atual.</p>
	</div>

	<div id="footer">Desenvolvimento Aberto ©
		desevolvimento.aberto@live.com</div>

</body>
</html>

404.jsp

<?xml version="1.0" encoding="ISO-8859-1" ?>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Desenvolvimento Aberto - 404</title>
</head>
<body>
	<h1>Desenvolvimento Aberto:</h1>
	<h3>Desculpe! Não encontramos a página solicitada no servidor.</h3>
</body>
</html>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	id="WebApp_ID" version="3.1">
	<display-name>DaRespostas</display-name>
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>index.htm</welcome-file>
		<welcome-file>index.jsp</welcome-file>
		<welcome-file>default.html</welcome-file>
		<welcome-file>default.htm</welcome-file>
		<welcome-file>default.jsp</welcome-file>
	</welcome-file-list>
	<error-page>
		<error-code>404</error-code>
		<location>/WEB-INF/404.jsp</location>
	</error-page>
</web-app>

SAP MaxDB é um banco de dados estratégico criado para rodar em todas as soluções SAP e substituir os bancos de dados Oracle, IBM DB2 e MSSQL Server  tornando as soluções SAP mais acessíveis em termos de custo para clientes de grande e médio porte. O SAP MaxDB foi construído como uma solução open source baseado em MySQL sob a licença GNU GPL, as versão anteriores do MaxDB ainda são mantidas pela comunidade open source mas a SAP não contribui mais com estas versões.

Ao longo dos últimos anos, a tecnologia SAP MaxDB continuou a evoluir com investimentos muito significativos em inovações e essas inovações não são em código aberto. Assim o mais recente produto SAP MaxDB não é open source, entretanto ele é gratuito em sua versão comunitária para uso com aplicações não SAP e possui licença comercial para uso com aplicações SAP.

Com 40 anos de inovação atuando em mais de 130 países e com mais de 100 mil clientes que utilizam soluções SAP, o SAP MaxDB ainda é um banco de dados jovem mas conta com mais de 6.500 clientes em 15.000 instalações mais soluções que utilizam liveCache e Content Server.

SAP MaxDB: http://maxdb.sap.com/

SAP MaxDB e C++ MFC

O C++ MFC utiliza as classes de fundação Microsoft e é a linguagem padrão para se desenvolver aplicativos Desktop C++ para Windows, você precisa no mínimo de uma versão profissional do Visual Studio para utilizar este framework.

A SAP disponibiliza uma API para utilizar o MaxDB com a linguagem de programação C++ utilizando os sistemas operacionais Unix, Linux e Windows, possibilitando integrar soluções Enterprise SAP que utilizam o banco de dados MaxDB com aplicações escritas em C++ ou permite que aplicações C++ utilizem o SAP MaxDB gratuitamente também em soluções que não possuem o intuito de integrar dados com os sistemas SAP.

Softwares Requeridos

Para utilizar este walkthrough completo integrando uma solução C++ com a linguagem de programação ABAP, você precisa instalar vários software entres eles o NetWeaver Application Server ABAP no qual já possui uma instalação completa do ambiente de desenvolvimento SAP com uma instancia do banco de dados MaxDB, caso queira utilizar somente o lado C++ você pode baixar o SAP MaxDB diretamente da SAP Store:

NetWeaver Application Server ABAP: Mini SAP

Download SAP MaxDB sistemas não SAP: SAP Store

SAP MaxDB SQL Studio: Desenvolvimento Aberto walkthrough

API C++ e  Drivers ODBC

Microsoft Fundation Classes permite utilizar suas classes para conectar ao MaxDB de um modo simples através do protocolo padrão ODBC, no entanto os drivers ODBC disponibilizados pela SAP não possuem a mesma arquitetura para aplicativos win32 (código nativo)  x64, então precisamos utilizar o driver 32bit disponibilizado pelo SAP MaxDB SQL Studio.

Caso não queira utilizar as classes MFC, a instalação do SAP MaxDB incluída nos produtos SAP como o núcleo de desenvolvimento do sistema SAP R/3 chamado de NetWeaver Application Sever ABAP já comtempla uma API C++ para que você possa acessar o banco de dados MaxDB e se encontra no seguinte local:

C:\sapdb\clients\NSP\sdk\sqldbc\incl
C:\sapdb\NSP\db\doc\FirstSteps\SQLDBC

Conectando ao MaxDB NSP com C++

1 – Caso utilize este tutorial com o NetWeaver primeiro tenha certeza que servidor de aplicação e a instancia SAP do banco de dados está rodando, caso utilize apenas o MaxDb e C++ ignore este passo:

SAP - Servidor de Aplicação - e Banco de dados - NetWeaver/MaxDB

SAP – Servidor de Aplicação – e Banco de dados – NetWeaver/MaxDB

2 – Abra o SQL Studio utilizando o servidor MaxDB e o banco de dados NSP ou seu próprio banco de dados caso não utilize o sistema SAP:

NSP - NetWeaver Database

NSP – NetWeaver Database

3 – Crie uma tabela Z que significa uma tabela não SAP Standard que não será transparente no conceito do dicionário de dados do sistemas SAP para isto utilize o script logo abaixo, não se assuste para desenvolvedores não SAP isto é apenas uma tabela comum do banco de dados:

Tabela Não Transparente

Tabela Z Não Transparente

4 – Utilizaremos os drivers ODBC do SAP MaxDB SQL Studio. No painel de controle escolha ferramentas administrativas e fonte de dados ODBC de 32bit, em drivers verifique seu driver NSP:

ODBC 32bit

ODBC 32bit

5 – Crie uma nova fonte de dados do usuário escolha o driver NSP ou o driver apropriado e clique em concluir:

ODBC SQLSTUDIO

ODBC SQLSTUDIO

6 – Preencha os dados de conexão com o servidor e o banco de dados e finalize:

Dados Servidor

Dados Servidor

7 – No Visual Studio crie uma solução MFC Dialog Based e disponha na tela um Static Text, um List Control e um Button, utilize a figura abaixo para o design:

Design Time

Design Time

8 – Utilize o código abaixo para manipular dados utilizando o SAP MaxDB:

C++ - Programa

C++ – Programa

9 – Para utilizar o ABAP para ler ou gravar dados nesta mesma tabela não transparente utilizando uma Stored Procedure no MaxDB através de códigos Native SQL, utilize o link abaixo:

Stored Procedure - Abap

Stored Procedure – Abap

Programa SAP – ABAP Native SQL: MaxDB Stored Procedure parâmetros IN e OUT

 Caso conecte em um banco de dados MaxDB utilizando soluções SAP tenha em mente que você deve respeitar o conceito de dados dos sistemas SAP e verificar os termos de garantia de cada produto SAP, visto que este método ao contrario do RFC  ignora a camada de banco de dados SAP e o dicionário de dados ABAP.

Como você pode verificar na imagem acima no ambiente ABAP o valor flutuante não vem formatado por padrão como estão acostumados os desenvolvedores SAP que utilizam instruções Open SQL e o dicionário ABAP no entanto você pode utilizar campos criados no dicionário apenas para a manipulação do valor de saída da Stored Procedure neste caso você deve alinhar os tipos de dados entre as aplicações C++ e aplicações ABAP.

Exemplo:

Neste exemplo utilizamos a linguagem de programação C++ para conectar ao banco de dados SAP MaxDB em uma instancia do banco de dados do NetWeaver e integrar uma tabela não transparente que pode ser manipulada tanto do lado C++ como dentro do sistema SAP utilizando Native SQL.

SQL – SAP MaxDB

-- Cria tabela no schema SAPNSP
CREATE TABLE SAPNSP.ZFUNCIONARIO
(
            ID_FUNCIONARIO INT,
            NOME VARCHAR (30),
            SOBRENOME VARCHAR(70),
            CARGO VARCHAR(30),
            SALARIO DECIMAL(9,2)
)

-- Insere dados na tabela
Insert into SAPNSP.ZFUNCIONARIO values (1,'Steve','Gates','Programador',2550.56)
Insert into SAPNSP.ZFUNCIONARIO values (2,'Bill','Jobs','Diretor',5143.71)

CPP – arquivo h


// ConexaoSapMaxDBcppDlg.h : header file
//

#pragma once

// Inclui classe de banco de dados MFC
#include "afxdb.h"
#include "afxcmn.h"

// CConexaoSapMaxDBcppDlg dialog
class CConexaoSapMaxDBcppDlg : public CDialogEx
{

public:
	CConexaoSapMaxDBcppDlg(CWnd* pParent = NULL);	// standard constructor
	enum { IDD = IDD_CONEXAOSAPMAXDBCPP_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support


protected:
	HICON m_hIcon;

	virtual BOOL OnInitDialog();
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	
	// Cria métodos e objetos da classe
	CDatabase db;
	void conectarDB(CString dns, CString usuario, CString senha);
	afx_msg void OnBnClickedButton1();
	CListCtrl m_tabela;
};

CPP – arquivo cpp


// ConexaoSapMaxDBcppDlg.cpp : implementation file
//

#include "stdafx.h"
#include "ConexaoSapMaxDBcpp.h"
#include "ConexaoSapMaxDBcppDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CConexaoSapMaxDBcppDlg dialog


CConexaoSapMaxDBcppDlg::CConexaoSapMaxDBcppDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CConexaoSapMaxDBcppDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CConexaoSapMaxDBcppDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST1, m_tabela);
}

BEGIN_MESSAGE_MAP(CConexaoSapMaxDBcppDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON1, &CConexaoSapMaxDBcppDlg::OnBnClickedButton1)
END_MESSAGE_MAP()


// CConexaoSapMaxDBcppDlg message handlers

BOOL CConexaoSapMaxDBcppDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	// Inicializa dialogo
	// Cria o modelo de exibição de dados
	m_tabela.SetView(LV_VIEW_DETAILS);
	m_tabela.SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_GRIDLINES);


	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CConexaoSapMaxDBcppDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

HCURSOR CConexaoSapMaxDBcppDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

void CConexaoSapMaxDBcppDlg::OnBnClickedButton1()
{
	// campo de dado da tabela
	CString m_campo;

	// Abre conexão
         // O SAP MAXDB requer usuário e senha em caracteres UPPERCASE
       	conectarDB(L"SAPMAXDB32", L"SAPNSP", L"PASSWORD");	

	// Cria um set de dados
	CRecordset  dados(&db);

	// Executa instrução SQL
	dados.Open(CRecordset::forwardOnly, L"Select * From SAPNSP.ZFUNCIONARIO Order by 1 DESC");
	

	// Cria item
	LVITEM lvItem;

	// cria estrutura para inserir o item
	typedef struct _LVITEM
	{
		UINT mask;
		int iItem;
		int iSubItem;
		UINT state;
		UINT stateMask;
		LPTSTR pszText;
		int cchTextMax;
		int iImage;
		LPARAM lParam;
#if (_WIN32_IE >= 0x0300)
		int iIndent;
#endif
	} LVITEM, FAR *LPLVITEM;

	// Define variaveis de itens
	int InsertItem(const LVITEM* pItem);
	int nItem;

	// Converte CString para LPTSTR atraves de um TCHAR
	TCHAR sz[1024];

	// Verifica colunas
	short nFields = dados.GetODBCFieldCount();
	int colunas = m_tabela.GetHeaderCtrl()->GetItemCount();

	// Verifica colunas
	if (colunas == 0)
	{
		// Lê metadata da tabela
		CODBCFieldInfo field;
		for (UINT i = 0; i < nFields; i++)
		{
			dados.GetODBCFieldInfo(i, field);
			m_tabela.InsertColumn(i, field.m_strName, LVCFMT_LEFT, 100);
		}

	}

	// Deleta itens do controle de lista
	m_tabela.DeleteAllItems();

	// Recupera dados da tabela
	while (!dados.IsEOF())
	{
		for (short index = 0; index < nFields; index++)
		{
			dados.GetFieldValue(index, m_campo);

			// Retorna linha do banco de dados
			if (index == 0)
			{
				// Insere linha
				lvItem.mask = LVIF_TEXT;
				lvItem.iItem = 0;
				lvItem.iSubItem = 0;
				lvItem.pszText = lstrcpy(sz, m_campo);
				nItem = m_tabela.InsertItem(&lvItem);
			}

			// Retorna colunas da linha
			m_tabela.SetItemText(nItem, index, lstrcpy(sz, m_campo));

		}
		// Move o cursor para a proxima linha
		dados.MoveNext();
	}

	// Fecha o set de dados e a conexão
	dados.Close();
	db.Close();

	
}

void CConexaoSapMaxDBcppDlg::conectarDB(CString dns, CString usuario, CString senha)
{
	// Cria string de conexão ODBC
	CString conexao;

	// Cria string de conexão
	conexao = L"DSN=" + dns + L";UID=" + usuario + L";PWD=" + senha;

	// Abre conexão
	db.OpenEx(conexao, 0);
}

SAP MaxDB é um banco de dados estratégico criado para rodar em todas as soluções SAP e substituir os bancos de dados Oracle, IBM DB2 e MSSQL Server  tornando as soluções SAP mais acessíveis em termos de custo para clientes de grande e médio porte. O SAP MaxDB foi construído como uma solução open source baseado em MySQL sob a licença GNU GPL, as versão anteriores do MaxDB ainda são mantidas pela comunidade open source mas a SAP não contribui mais com estas versões.

Ao longo dos últimos anos, a tecnologia SAP MaxDB continuou a evoluir com investimentos muito significativos em inovações e essas inovações não são em código aberto. Assim o mais recente produto SAP MaxDB não é open source, entretanto ele é gratuito em sua versão comunitária para uso com aplicações não SAP e possui licença comercial para uso com aplicações SAP.

Com 40 anos de inovação atuando em mais de 130 países e com mais de 100 mil clientes que utilizam soluções SAP, o SAP MaxDB ainda é um banco de dados jovem mas conta com mais de 6.500 clientes em 15.000 instalações mais soluções que utilizam liveCache e Content Server.

SAP MaxDB: http://maxdb.sap.com/

SAP MaxDB e C#

A SAP disponibiliza provedores para utilizar o MaxDB com as linguagens de programação .NET utilizando os sistemas operacionais Unix, Linux e Windows, possibilitando integrar soluções Enterprise SAP que utilizam o banco de dados MaxDB com aplicações escritas em C# ou permite que aplicações C# utilizem o SAP MaxDB gratuitamente também em soluções que não possuem o intuito de integrar dados com os sistemas SAP.

SAP ADO.NETInterface ADO.NET

Para utilizar este walkthrough completo integrando uma solução C# com a linguagem de programação ABAP, você precisa instalar vários software entres eles o NetWeaver Application Server ABAP no qual já possui uma instalação completa do ambiente de desenvolvimento SAP com uma instancia do banco de dados MaxDB, caso queira utilizar somente o lado C# você pode baixar o SAP MaxDB diretamente da SAP Store:

NetWeaver Application Server ABAP: Mini SAP

Download SAP MaxDB sistemas não SAP: SAP Store

SAP MaxDB SQL Studio: Desenvolvimento Aberto walkthrough

MaxDB Data Provider ADO.NET e MONO

O provedor ADO.NET for MaxDB RDBMS foi desenvolvido pelo projeto MONO sob a licença GNU para as versões open Source do SAP MaxDB, caso queira utilizar provedores das versões disponibilizadas pela SAP, estas já acompanham a instalação do MaxDB.

Download: http://sourceforge.net/projects/maxdbprovider/

Projeto MaxDB Mono: http://www.mono-project.com/archived/maxdb/

Conectando ao MaxDB em instancia SAP com C#

1 – Caso utilize este tutorial com o NetWeaver primeiro tenha certeza que servidor de aplicação e a instancia SAP do banco de dados está rodando, caso utilize apenas o MaxDb e C# ignore este passo:

SAP - Servidor de Aplicação - e Banco de dados - NetWeaver/MaxDB

SAP – Servidor de Aplicação – e Banco de dados – NetWeaver/MaxDB

2 – Abra o SQL Studio utilizando o servidor MaxDB e o banco de dados NSP ou seu próprio banco de dados caso não utilize o sistema SAP:

NSP - NetWeaver Database

NSP – NetWeaver Database

3 – Crie uma tabela Z que significa uma tabela não SAP Standard que não será transparente no conceito do dicionário de dados do sistemas SAP para isto utilize o script logo abaixo, não se assuste para desenvolvedores não SAP isto é apenas uma tabela comum do banco de dados:

Tabela Não Transparente

Tabela Z Não Transparente

4 – Após efetuar o download do provedor ADO.NET para MaxDB clique com o botão direito do mouse, desbloqueie o arquivo baixado, pois o arquivo foi compilado no Linux, caso contrario o Windows Smart Screen tentara bloquear o arquivo. Clique em instalar:

SAP MaxDb Provider for .NET

SAP MaxDb Provider for .NET

5 – Crie um projeto Windows Forms e disponha na tela um Label, um DataGridView e um Button e alinhe os componentes como na figura abaixo:

Design Time

Design Time

6 – Compile o programa e clique em conectar para se conectar a instancia SAP NSP:

Programa C#

Programa C#

7 – Para utilizar o ABAP para ler ou gravar dados nesta mesma tabela não transparente utilizando uma Stored Procedure no MaxDB através de códigos Native SQL, utilize o link abaixo:

Stored Procedure - Abap

Stored Procedure – Abap

Programa SAP – ABAP Native SQL: MaxDB Stored Procedure parâmetros IN e OUT

 Caso conecte em um banco de dados MaxDB utilizando soluções SAP tenha em mente que você deve respeitar o conceito de dados dos sistemas SAP e verificar os termos de garantia de cada produto SAP, visto que este método ao contrario do RFC  ignora a camada de banco de dados SAP e o dicionário de dados ABAP.

Como você pode verificar na imagem acima no ambiente ABAP o valor flutuante não vem formatado por padrão como estão acostumados os desenvolvedores SAP que utilizam instruções Open SQL e o dicionário ABAP no entanto você pode utilizar campos criados no dicionário apenas para a manipulação do valor de saída da Stored Procedure neste caso você deve alinhar os tipos de dados entre as aplicações C# e aplicações ABAP.

Exemplo:

Neste exemplo utilizamos a linguagem de programação C# para se conectar ao banco de dados SAP MaxDB em uma instancia do banco de dados do NetWeaver e integrar uma tabela não transparente que pode ser manipulada tanto do lado C# como dentro do sistema SAP utilizando Native SQL.

SQL – SAP MaxDB

-- Cria tabela no schema SAPNSP
CREATE TABLE SAPNSP.ZFUNCIONARIO
(
            ID_FUNCIONARIO INT,
            NOME VARCHAR (30),
            SOBRENOME VARCHAR(70),
            CARGO VARCHAR(30),
            SALARIO DECIMAL(9,2)
)

-- Insere dados na tabela
Insert into SAPNSP.ZFUNCIONARIO values (1,'Steve','Gates','Programador',2550.56)
Insert into SAPNSP.ZFUNCIONARIO values (2,'Bill','Jobs','Diretor',5143.71)

C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using MaxDB.Data; // SAP MaxDB Data Provider for MONO 

namespace WindowsFormsApplication1
{
    public partial class FormMaxDB : Form
    {
        
        // Declara objetos
        private static MaxDBConnection connMaxDB;   // MaxDB Data Server Provider for MONO        
        private DataTable dataTable;
        string sql;
        
        // Conexão MaxDB
        void conexaoMaxDB(string Server, string Database,
                                    string Username, string Password)
        {
            try
            {
                // String de Conexao
                string connectionString =

                    // Servidor
                    "Server=" + Server +

                    // Banco de dados
                    ";Database=" + Database +

                    // Usuario
                    ";User ID=" + Username +

                    // Senha
                    ";Password=" + Password;

                //Conecta ao datasource usando a conexão SAP MaxDB
                connMaxDB = new MaxDBConnection(connectionString);

                //Abre a conexão com o banco de dados
                connMaxDB.Open();

            }
            // Retorna erro
            catch (Exception ex)
            {
                // Mostra menssagem de erro
                MessageBox.Show(ex.ToString());
            }
        }

        // Retorna um set de dados
        public DataTable retornaTabela(string sql)
        {
            FormMaxDB acesso = new FormMaxDB();

            // SAP MaxDB requer usuario e senha em caracteres UPPERCASE
            acesso.conexaoMaxDB("localhost", "NSP", "SAPNSP", "PASSWORD");

            // Cria comando SQL
            MaxDBCommand maxCmd = new MaxDBCommand(sql);
            maxCmd.Connection = connMaxDB;
            
            // Cria DataReader
            MaxDBDataReader maxDBreader = maxCmd.ExecuteReader();
            dataTable = new DataTable();
            dataTable.Load(maxDBreader);
            
            return dataTable;
        }

        public FormMaxDB()
        {
            InitializeComponent();
        }
        
        private void button1_Click(object sender, EventArgs e)
        {
            // Alimenta grade de dados
            FormMaxDB dados = new FormMaxDB();            
            dataGridView1.DataSource = dados.retornaTabela("Select * from SAPNSP.ZFUNCIONARIO");
        }
    }
}