Tuesday, February 19, 2013

Aplicações 3 camadas com o OpenSwing - parte 2

Dando continuidade à Parte 1 deste artigo, na qual criamos a estrutura dos projetos  AplicaçãoServidor e AplicacaoCliente, vamos estabelecer a comunicação entre ambos.

No projeto web AplicaçãoServidor crie um pacote chamado controle. Dentro desse pacote crie 4 classes cujos nomes são os que seguem:
  • ActionClasses
  • MyControllerCallBack
  • XMLResources
  • MyActions
Observe a estrutura na aba de projetos do NetBeans:


O código das classes MyControllerCallBack e XMLResources é um padrão do OpenSwing e não varia, é, portanto, sempre o mesmo para qualquer aplicação.

A interface org.openswing.swing.server.Action  é quem recebe diretamente a requisição do cliente. Ela assina dois métodos: executeCommand() e getRequestName(), este último retorna uma string com o nome da implementação, de modo que o cliente use este nome como parâmetro, indicando que a requisição deve ir para esta classe. O desenvolvedor pode criar quantas implementações quiser para Action, de acordo com as regras de negócio estabelecidas.

Para o projeto AplicaçãoServidor, o código das classes deve ser exatamente como que segue:
package controle;

import javax.servlet.ServletContext;
import org.openswing.swing.server.ControllerCallbacks;

/**
 *
 * @author OS
 * 
 * class of type org.openswing.swing.server.ControllerCallbacks , an application specific class that contains additional initialization logic for the web application.
 * The afterInit() method of this interfacce is automatically invoked by the Controller servlet after its initialization and can be used to add further logic, 
 * that depends on the specific application.
 */
public class MyControllerCallBack extends ControllerCallbacks{

    public MyControllerCallBack() {
    }

    @Override
    public void afterInit(ServletContext context) {
        
    }            
}
XMLResources.java
package controle;

import org.openswing.swing.internationalization.java.XMLResourcesFactory;
import org.openswing.swing.internationalization.server.ServerResourcesFactory;
import java.util.Hashtable;
import org.openswing.swing.internationalization.java.Resources;
import javax.servlet.ServletContext;

/**
 * Internacionalizacao suporte
 */
public class XMLResources extends ServerResourcesFactory {

  private XMLResourcesFactory factory = null;

  public XMLResources() {
  }

  /**
   * Method called by the server controller (Controller object) to initialize the factory.
   * @param context
   */
    @Override
  public void init(ServletContext context) {
    Hashtable xmlFiles = new Hashtable();
    //xmlFiles.put("EN",this.getClass().getResource("/").getPath()+"Resources_en.xml");
    //xmlFiles.put("IT",this.getClass().getResource("/").getPath()+"Resources_it.xml");
    factory = new XMLResourcesFactory(xmlFiles,true);
  }


  /**
   * Load dictionary, according to the specified language id.
   * @param langId language id identifier
   */
    @Override
  public final void setLanguage(String langId) throws UnsupportedOperationException {
    factory.setLanguage(langId);
  }


  /**
   * @return internationalization settings, according with the current language
   */
    @Override
  public final Resources getResources() {
    return factory.getResources();
  }


  /**
   * @param langId language id identifier
   * @return internationalization settings, according with the language specified
   */
    @Override
  public final Resources getResources(String langId) throws UnsupportedOperationException {
    return factory.getResources(langId);
  }
  
}  
A classe org.openswing.swing.server.ActionsCollections estende Hashtable.  Cada implementação da interface Action deve ser inserida nesta Collection, onde a chave é definida pelo retorno do método getRequestName(), e o valor é a própria instancia de Action.
ActionClasses.java:
package controle;

import org.openswing.swing.server.Action;
import org.openswing.swing.server.ActionsCollection;

public class ActionClasses extends ActionsCollection {

    public ActionClasses() {
        
        Action action = null;
        
        action = new MyActions();
        put(action.getRequestName(), action);
        
    }            
}
Como foi dito, você pode criar quantas implementações quiser para a interface Action, de acordo com as regras de negócio da aplicação. Neste exemplo, a regra é retornar ao cliente um objeto do tipo org.openswing.swing.message.receive.java.Response que encapsula a string Hello World From Server!.

MyActions.java
package controle;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.openswing.swing.message.receive.java.Response;
import org.openswing.swing.message.receive.java.TextResponse;
import org.openswing.swing.server.Action;
import org.openswing.swing.server.UserSessionParameters;

public class MyActions implements Action{

    @Override
    public Response executeCommand(Object inputPar, 
                                        UserSessionParameters userSessionPars, 
                                        HttpServletRequest request, 
                                        HttpServletResponse response, HttpSession userSession, ServletContext context) {
        
        
        Object[] clientParams = (Object[]) inputPar;
        
        String methodName = (String) clientParams[0];
        
        if(methodName.equals("enviarHelloWorld")){
            //sempre uma implementação da classe abstrata Response deve ser retornada ao cliente            
            return new TextResponse("Hello World From Server!");
        }
        return null;
    }

    @Override
    public String getRequestName() {
        return "MyActions";
    }    
}
Agora você deve definir a implementação dessas classes como parêmetros de inicialização da Servlet controller do OpenSwing, adicionando as tags corespondentes ao arquivo web.xml. Veja como fica a versão final do mesmo:

    
    
        controller
        org.openswing.swing.server.Controller                    
        
            sessionIdGenerator
            org.openswing.swing.server.DefaultSessionIdGenerator
        
        
            logger
            org.openswing.swing.logger.server.ConsoleLogger
                
        
            objectsReceiver
            org.openswing.swing.util.server.HessianObjectReceiver
           
        
     connectionSource
            org.openswing.swing.server.PoolerConnectionSource
        
        
        
        
            controllerCallback
            controle.MyControllerCallBack
        
        
            resourceFactory
            controle.XMLResources
        
        
            actionClasses
            controle.ActionClasses
                
        
        1
    
    
    
        50
    
    
    
        
        controller
        /controller
                        
  
Aplicação Cliente

O projeto AplicacaoCliente envia uma requisição ao servidor, se tudo correr bem, recebe de volta um objeto do tipo org.openswing.swing.message.receive.java.Response que encapsula a mensagem Hello WorldFrom Server! em um painel de diálogo.

No pacote cliente do projeto crie a classe principal ClientApplication. O código é como segue:
package cliente;

import java.util.Hashtable;
import java.util.Properties;
import javax.swing.JOptionPane;
import org.openswing.swing.internationalization.java.BrazilianPortugueseOnlyResourceFactory;
import org.openswing.swing.message.receive.java.Response;
import org.openswing.swing.message.receive.java.TextResponse;
import org.openswing.swing.util.client.ClientSettings;
import org.openswing.swing.util.client.ClientUtils;
import org.openswing.swing.util.client.HessianObjectSender;

public class ClientApplication {
    
    public static void main(String[] args) throws Exception{
        //url do servidor
        String serverUrl = "http://localhost:8082/AplicacaoServidor/controller";
        setConexaoServidor(serverUrl);
                
        String serverSideActionClassName = "MyActions";
        String methodName = "enviarHelloWorld";
        
        Response serverResponse = ClientUtils.getData(serversideActionClassName, new Object[]{methodName});                
        
        if(serverResponse.isError())
            throw new Exception("Erro ao conectar o servidor");
    
        //recebe o texto de resposta
        String serverMessage = ((TextResponse)serverResponse).getMessage();
    
        JOptionPane.showMessageDialog(null, serverMessage);        
    }

    //configura a conxão remota
    private static void setConexaoServidor(String serverUrl) {        
        System.setProperty("SERVERURL", serverUrl);
        ClientUtils.setObjectSender(new HessianObjectSender());
        ClientSettings clientSettings = 
                new ClientSettings(
                           new BrazilianPortugueseOnlyResourceFactory(new Properties(), false), 
                           new Hashtable()
                );
    }
}
Execute o projeto AplicacaoCliente para exibir a mensagem recebida:


Para uma referência mais detalhada, consulte a página do OpenSwing.

Monday, January 21, 2013

Aplicações 3 camadas com o OpenSwing - parte 1

OpenSwing é um framework Java open source destinado principalmente ao o desenvolvimento de aplicações gráficas desktop. Ele reúne uma suíte de componentes visuais baseados na API Swing tradicional, porém seus componentes são um pouco mais avançados do que o Swing toolkit a medida em que eles provêem uma série de recursos adicionais - ou recursos prontos - visando facilitar e agilizar o desenvolvimento de aplicações comerciais.

Dentre esses recursos podemos citar o binding entre tabelas e formulários, e os objetos do modelo negócios; botões prontos para as funções de CRUD;   uma template que agiliza a crição de aplicções MDI (Multiple Document Interface); entre outros.

Para um exemplo mais detalhado sobre os recursos citados consulte a src demo do framework na página de download do mesmo. Thiago Vespa também exemplifica de maneira interessante esses recursos.

Desenvolvimento do lado do servidor

Embora os componentes para desenvovimento desktop sejam mais úteis e produtivos do que os componentes Swing tradicionais, eles não são, na minha opinião, o recurso mais interessante disponíbilizado pelo OpenSwing.

O recurso mais interessante na minha opinião é a possibilidade de desenvolver aplicações Swing com  processamento do lado do servidor de maneira muito simples. O programador sequer precisa utilizar diretamente as classes networking de Java, nem Servlets, para estabelecer essa conexão. Segue um projeto de exemplo passo-a-passo:

Faça download da versão 2.4.5 do OpenSwing em sourceforge.net/projects/oswing/files/oswing/.

Abra sua IDE favorita (estou utilizando NetBeans 7.2) e crie um projeto web chamado AplicaçãoServidor e outro projeto desktop chamado AplicacaoCliente. Para o projeto web utlizei o servidor Apache Tomcat 7.0.34. Observe a estrutura dos projetos recém criados:



Agora você deve adiconar ao classpath dos projetos as classes do framework OpenSwing. Elas estão no diretório build da pasta que você acabou de baixar, OpenSwing2.4.5.

Aplicação Web

O arquivo web.xml de sua aplicação web deve ficar como segue (para mais detalhes sobre a função de cada tag, consulte a documentação online em oswing.sourceforge.net/server.html):

    
    
        controller
        org.openswing.swing.server.Controller                    
        
            sessionIdGenerator
            org.openswing.swing.server.DefaultSessionIdGenerator
        
        
            logger
            org.openswing.swing.logger.server.ConsoleLogger
                
        
            objectsReceiver
            org.openswing.swing.util.server.HessianObjectReceiver
           
        
     connectionSource
            org.openswing.swing.server.PoolerConnectionSource
        
        1
    
    
    
        50
    
    
    
        
        controller
        /controller
                        
    

Agora faça o deploy de sua aplicação web. Em seguida acesse a seguinte url no seu browser: http://localhost:8082/AplicacaoServidor/controller (meu tomcat está na porta 8082). Se você visualizar a seguinte mensagem, sua aplicação foi publicada corretamente:




Na Parte 2 deste post daremos continuidade ao exemplo, estabelecendo a comunicação entre a aplicação cliente e apĺicação do lado do servidor.

Friday, January 18, 2013

Problemas na sugestão automática de "imports" no NetBeans 7.2

Para minha surpresa, recentemente percebi que a sugestão automática de imports no NetBeans 7.2 não estava mais funcionando para classes do pacote java.*. Por exemplo, caso eu digitasse:
class A implements Serializable{}
A única dica fornecida pela IDE era perguntar se desejava criar a interface Serializable no pacote atual, ou seja, faltava a sugestão deseja importar java.io.Serializable. Nos dias atuais ninguém quer ficar escrevendo declarações de import :)

Felizmente parece que o problema foi resolvido limpando o cache do NetBeans. No Linux, fechei a IDE e apenas executei o seguinte comando:
sudo rm -rf ~/.cache/netbeans/7.2/*
Ao abrir a IDE novamente, o recurso de importação automática voltou a funcionar corretamente para todos os pacotes.