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.