Android + AOP + kSOAP – Pt.4: Construindo Serviços Dinâmicos

Publicado por Fabio A. Falavinha
31/10/2011
Categoria:
Tags: , , , ,

Olá pessoALL!

Os últimos artigos da série Android+kSOAP, escritos por Bruno Silva, introduziram o conceito de integração entre aplicações android com web services, através de parses dinâmicos, cache e modularização/encapsulamento de elementos dentro de um conceito EAI (Enterprise Application Integration).

Este artigo tem como objetivo a criação dinâmica de serviços sem a implementação do mesmo. Estranho, não é? Não é estranho até adicionarmos o conceito AOP (Aspect Oriented Programming) à solução de integração.

Como o foco deste artigo não é AOP, fica como sugestão a leitura do artigo AOP com Spring.NET. Este artigo cobre o conceito de AOP, no qual estaremos mencionando nos próximos tópicos.

AOP

AOP é um conceito simples, porém com alguns níveis de implementação:

  • Linguagem de Programação: utilizar uma linguagem de programação que permite a construção de aspectos e acesso a recursos em tempo de execução e troca de mensagens entre os objetos em uma máquina virtual (por exemplo: Java Virtual Machine).
  • Proxy: utilizar o mecanismo de Proxy de uma linguagem de programação para criar objetos dinamicamente com atuação de um controle (handler) nas chamadas de métodos destes objetos.

O nível de implementação que vamos utilizar neste artigo é Proxy. Vamos utilizar a classe:

java.lang.reflect.Proxy

Construindo Web Service

Antes de começar a criação dos serviços do lado da aplicação android, vamos criar o web service que realizará os processamentos de nossas chamadas.

Vou criar um serviço simples, utilizando a tecnologia .NET WCF (Windows Communication Foundation):

    [ServiceContract]
    public interface ISimpleService
    {
        [OperationContract]
        string ProcessData(int value);

        [OperationContract]
        string GetData();
    }

A implementação do serviço será:

    public class SimpleService : ISimpleService
    {
        public string ProcessData(int value)
        {
            return string.Format("You entered: {0}", value);
        }

        public string GetData()
        {
            return "Some Data!";
        }
    }

O serviço será publicado locamente para acesso da aplicação android.

Acessando Serviços

Com o web service SimpleService publicado, vamos criar a solução para acesso aos seus dados, levando em consideração o conceito AOP.

A primeira parte será criar anotações para permitir o armazenamento de informações metadata do serviço que iremos acessar. Como assim? Criaremos uma anotação para o serviço e outra para as operações do serviço, respectivamente:

@Target (ElementType.TYPE )
@Retention (RetentionPolicy.RUNTIME)
public @interface SOAPService {

      String serverUrl() default "";
      String namespace() default "http://tempuri.org";
      String serviceName();
      String serviceInterface() default "";

}

Vejam, que esta anotação permite as seguintes informações em nível de serviço:

  • serverURL: endereço do servidor que está publicado o web service.
  • namespace: nome do contexto que está publicado o serviço.
  • serviceName: nome do serviço publicado.
  • serviceInterface: nome da interface do serviço publicado.
@Target (ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SOAPServiceOperation {

      String name() default "";
      Class parser();
      String[] parameterNames() default {};

}

Já, esta anotação, permite informações em nível de operação de serviço:

  • name: nome da operação.
  • parser: implementação da interface IMethodResponseParser (veja o artigo Android+kSOAP – Pt.3).
  • parameterNames: conjunto de nomes que simboliza os paramêtros a serem enviados, como argumentos, na operação.

Com as anotações criadas, vamos criar a interface do serviço que acessará o web service:

@SOAPService(namespace="http://tempuri.org",
			 serverUrl="http://localhost:51827",
			 serviceInterface="ISimpleService",
			 serviceName="SimpleService")
public interface DummyService {

	@SOAPServiceOperation(name="GetData", parser=DummyServiceParser.class)
	String getData();

}

Pronto! Criamos uma interface que será utilizada para criar serviços, de forma dinâmica, baseados no WSDL do web service.

Notem, que a classe de conversão – DummyServiceParser – é uma implementação da interface, já conhecida, dos artigos anteriores, IMethodResponseParser.

public class DummyServiceParser implements IMethodResponseParser {

	@Override
	public Object parse(SoapObject soapObject, SoapMapper soapMapper) {
		return soapMapper.parseSoapObjectIntoAnnotatedVO(DummyObject.class, soapObject);
	}

}

Agora, precisamos construir o mecanismo para gerar serviços, via Proxy, incluindo um controle de chamadas para as invocações de metódos destes objetos. Este mecanismo será uma factoryServiceFactory – que criará Proxy com o seguinte controle de chamadas – ServiceInvocationHandler.

public final class ServiceFactory {

	private static final ServiceFactory instance = new ServiceFactory();

	private final <strong>ServiceInvocationHandler</strong> invocationHandler;

	private ServiceFactory() {
		invocationHandler = new ServiceInvocationHandler();
	}

	public static ServiceFactory getInstance() {
		return instance;
	}

	public Object newService(Class<?> serviceInterfaceType) throws MalformedURLException {
		if (!serviceInterfaceType.isInterface()) {
			throw new IllegalArgumentException("Invalid type argument. Proxy service instance are created based on interface types.");
		}
		final ServiceInterfaceData serviceData = SoapAnnotationDataCache.addServiceInterface(serviceInterfaceType);
		final URL url = serviceData.getServerUrl();
		if (url == null) {
			throw new MalformedURLException("Invalid server URL. Make sure that you set the [serverUrl] attribute from [" + SOAPService.class.getSimpleName() + "] annotation.");
		}
		return Proxy.newProxyInstance(ServiceFactory.class.getClassLoader(), new Class<?>[] { serviceInterfaceType }, this.invocationHandler);
	}

}

Percebam, que a implementação do método ServiceFactory.newInstance utiliza a solução de cache do artigo Android+kSOAP – Pt.1. É anexado ao Proxy o controle de chamadas ServiceInvocationHandler.

public final class ServiceInvocationHandler implements InvocationHandler {

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		final ServiceInterfaceData serviceData = SoapAnnotationDataCache.getServiceInterfaceData(method);
		final ServiceMethodData methodData = serviceData.getMethodData(method);
		final String[] parameterNames = methodData.getParameterNames();
		final LinkedHashMap<String, Object> params = new LinkedHashMap<String, Object>();
		if (args != null && args.length != parameterNames.length) {
			throw new IllegalArgumentException("The parameter names array length is different then invocation method arguments.");
		}
		if (args != null && parameterNames.length > 0) {
			for (int i = 0; i < args.length; ++i) {
				params.put(parameterNames[i], args[i]);
			}
		}
		return new Caller<Object>()
			.setParams(params)
			.setServerUrl(serviceData.getServerUrl())
			.setNamespace(serviceData.getNamespace())
			.setService(serviceData.getServiceName())
			.setServiceInterface(serviceData.getServiceInterface())
			.setMethod(methodData.getName())
			.setResponseParser(methodData.getParser()).call();
	}

}

Mais uma vez, estou utilizando um elemento já conhecido, na série de artigos Android+kSOAP, o elemento Caller. Portanto, toda chamada realizada no Proxy, será direcionada ao controle de chamadas, que executará o acesso ao web service. O resultado da operação será convertido pela classe DummyServiceParser, anotada na operação do serviço.

Conclusão

Simplificar acesso a web service ou a recursos externos, utilizando conceitos de EAI, é primordial para evolução de softwares que necessitam deste tipo de solução.

Vejam, que no decorrer do artigo não mencionei sobre conversão e transformação automática dos dados enviados e retornados. Toda conversão é realizada por um parser, o que poderia ser um processo transparente para a utilização desta solução.

Uma solução open-source é a utilização da biblioteca ASoap. Esta biblioteca permite acesso de forma transparente, juntamente com a conversão e transformação de dados de um modo simples e flexível. Vale a pena dar uma olhada!

É isso aí pessoALL, fico por aqui!

Referências

4 Comentários

  • Reply

    Por GUSTAVO ROSSI MULLER em 1 de December de 2012 às 20:23

    Boa noite,

    Gostei do seu artigo e dos artigos do Bruno, muito bons.

    Você pode mostra um exemplo de como usar a biblioteca ASOAP para consumir o ws abaixo?

    http://webservices.daehosting.com/services/eleventest.wso?op=IsAllNumbers

  • Reply

    Por Fabio A. Falavinha em 14 de December de 2012 às 16:14

    Oi Gustavo, segue um link para download de um exemplo:

    https://docs.google.com/folder/d/0B3AIYF-EW9fjWFRibm1IU2dkTTA/edit

    A partir do WSDL crie as classes que serão parte do parser do asoap, assim como no exemplo, você pode ver pela classe DummyObject.
    Crie uma interface e anote-a usando as anotações do asoap, use o exemplo da classe DummyService.
    Para realizar um teste de chamada ao serviço, veja no exemplo da classe ServiceTest, que ao chamar a classe ServiceFactory.newService(…), você terá um proxy em cima da sua interface para realizar as requisições.

    Faça o código e poste aqui para que eu possa lhe ajudar.
    Um grande abraço!

  • Reply

    Por gil em 27 de August de 2014 às 18:20

    Olá boa noite não sei se nessa pastagem e o lugar certo. Mas preciso esclarecer essa dúvida com vocês. Estou desenvolvendo meu tcc que se trata de um sistema para gestão de academias e um app para alunos acessarem os treinos. Porém o prazo está muito curto pra criar o app nativo em Android li em alguns artigos que é possível criar um app Android que na verdade é apenas uma casca do app as funcionalidades estão todas no site por exemplo. Alguém poderia falar sobre isso ou indicar alguma referência.

    Meu email: gil-real@hotmail.com

    muito grato pela atenção.

  • Reply

    Por Fabio A. Falavinha em 27 de February de 2015 às 14:15

    Olá Gil,

    Peço desculpas por responder apenas agora.

    Acesse o link abaixo para entender como o desenvolvimento nativo (específico para uma ou mais plataformas) ou cross-platform (mesmo código, porém distribuído para várias plataformas).

    http://martinfowler.com/articles/multiMobile/





Desenvolvido por hacklab/ com WordPress