Programação Orientada a Objetos Desenvolvimento de Software Orientado a Aspectos Lida com conceitos mais intuitivos Permite ganhos • Reuso • Manutenção • Adaptação Sérgio Soares [email protected] Padrões de projetos • Auxiliam a POO Sérgio Castelo Branco Soares ESCOLA POLITÉCNICA 1 DE PERNAMBUCO Exemplo: Sistema Disque Saúde Exemplo: Sistema Disque Saúde Um sistema de informação Implementado em Java • Registra e encaminha queixas para o sistema de saúde • Exibe informações sobre unidades de saúde e suas especialidades • Servlets implementam a GUI • Utiliza vários padrões de projetos para contemplar requisitos não-funcionais Requisitos não-funcionais • Distribuído • Acesso concorrente • Extensível Como implementar a distribuição no sistema? —Armazenamento de dados —Tecnologia de distribuição Sérgio Castelo Branco Soares 2 Sérgio Castelo Branco Soares 3 4 Sérgio Castelo Branco Soares Disque Saúde distribuído com RMI Disque Saúde local public class Complaint implements java.io.Serializable { public class HealthWatcherFacade implements IFacade { private String description; public class ServletUpdateComplaintData extends HttpServlet { public void update(Complaint complaint) private Person complainer; ... private IFacade facade; throws TransactionException, RepositoryException, public Complaint(String description, Person complainer, ...) { public void init(ServletConfig config) throws ServletException { ObjectNotFoundException, ObjectNotValidException { try { ... ... facade = (IFacade) java.rmi.Naming.lookup("//HealthWatcher"); } } } public static void main(String[] args) { public String getDescription() { catch (java.rmi.RemoteException rmiEx) {...} try { return this.description; catch (java.rmi.NotBoundException rmiEx) {...} HealthWatcherFacade facade = HealthWatcherFacade.getInstance(); } catch (java.net.MalformedURLException rmiEx) {...} System.out.println("Creating RMI server..."); public Person getComplainer() { } UnicastRemoteObject.exportObject(facade); return this.complainer; java.rmi.Naming.rebind("/HealthWatcher"); } System.out.println("Server created and ready."); public void setDescription(String desc) { public void doPost(HttpServletRequest request, HttpServletResponse response) } this.description = desc; throws ServletException, IOException { catch (RemoteException rmiEx) {... } } ... catch (MalformedURLException rmiEx) { ...} public void setComplainer(Person complainer) { } ... facade.update(complaint); catch(Exception ex) {... } this.complainer = complainer; ... } } ... } } } public class Person implements java.io.Serializable { public interface IFacade extends java.rmi.Remote { private String nome; ... public Person(String nome, …) { public void updateComplaint complaint) this.nome = nome; … throws TransactionException, RepositoryException, } ObjectNotFoundException, ObjectNotValidException, public String getNome() { RemoteException; return nome; }… ... } } Código RMI é vermelho… Sérgio Castelo Branco Soares 5 Sérgio Castelo Branco Soares 6 1 AOP — Aspect-oriented programming Implementação OO: problemas! Tangled code (código entrelaçado) • código de distribuição misturado com código de negócio e de GUI • distribuição, gerenciamento de dados, controle de concorrência, tratamento de exceções, logging, debugging, … Spread code (código espalhado) • código de distribuição em várias classes Distribuição é um crosscutting concern (interesse transversal) Difícil de manter e reusar • mudanças no protocolo de distribuirão (RMI, CORBA, EJB ) são invasivas Sérgio Castelo Branco Soares Melhora a modularidade de interesses transversais Auxilia separação de interesses (separation of concerns) • aumenta extensibilidade e reuso 7 Disque Saúde distribuído com AOP (usando Java RMI) 8 Sérgio Castelo Branco Soares Disque Saúde distribuído com AOP public class Complaint { private String description; private Person complainer; ... public class ServletUpdateComplaintData extends HttpServlet { public Complaint(String description, Person complainer, ...) { aspect DistributionAspect { private HealthWatcherFacade facade; declare parents: HealthWatcherFacade implements IFacade; public void init(ServletConfig config) throws ServletException { declare parents: Complaint || Person implements java.io.Serializable; ... try { } public static void HealthWatcherFacade.main(String[] args) { facade = HealthWatcherFacade.getInstance(); public String getDescription() { try { } return this.description; HealthWatcherFacade facade = HealthWatcherFacade.getInstance(); catch (Exception ex) {...} } System.out.println("Creating RMI server..."); } public Person getComplainer() { return this.complainer; UnicastRemoteObject.exportObject(facade); public void doPost(HttpServletRequest request, HttpServletResponse response) } java.rmi.Naming.rebind("/HealthWatcher"); System.out.println("Server created and ready."); throws ServletException, IOException { public void setDescription(String desc) { this.description = desc; } } catch (RemoteException rmiEx) {...} ... catch (MalformedURLException rmiEx) {...} } ... catch(Exception ex) {...} } } public void setComplainer(Person complainer) { this.complainer = complainer; } } public class Person { private String nome; ... public Person(String nome, ...) { this.matricula = matricula; ... } public String getNome() { return nome; private IFacade remoteFacade; Sistema local pointcut facadeMethodsExecution(): within(HttpServlet+) && execution(* HealthWatcherFacade.*(..)) && this(HealthWatcherFacade); before(): facadeMethodsExecution() { prepareFacade();} Aspectos de distribuição com RMI private synchronized void prepareFacade() { if (healthWatcher == null) { try { remoteFacade = (IFacade) java.rmi.Naming.lookup("//HealthWatcher"); } catch (java.rmi.RemoteException rmiEx) {...} catch (java.rmi.NotBoundException rmiEx) {...} catch (java.net.MalformedURLException rmiEx) {...} } } ... void around(Complaint complaint) throws TransactionException, RepositoryException } ObjectNotFoundException,ObjectNotValidException: public interface IFacade extends java.rmi.Remote { facadeRemoteExecutions() && args(complaint) && public class HealthWatcherFacade { try { remoteFacade.update(complaint); throws TransactionException, RepositoryException, throws TransactionException, RepositoryException, } catch (RemoteException rmiEx) {...} ObjectNotFoundException, ObjectNotValidException, ObjectNotFoundException, ObjectNotValidException { } RemoteException; ... ... } call(void update(Complaint)) { public void updateComplaint complaint) public void update(Complaint complaint) } } } Sérgio Castelo Branco Soares 9 10 Sérgio Castelo Branco Soares Implementação com AOP Aumento em modularidade, reuso e extensibidade Em direção ao Desenvolvimento de Software • Mais unidades de código • Mudanças no sistema local podem causar impacto nos aspectos de distribuição Separation of concerns (separação de Orientado a Aspectos (DSOA) interesses) • Relação entre os aspectos e o resto do sistema nem sempre é clara Normalmente menos linhas de código Sérgio Castelo Branco Soares 11 Sérgio Castelo Branco Soares 12 2 Passo 1: Identificando interesses (decomposição) Identificador de interesses Interesses do Disque Saúde Interface com o usuário Interesses Gerenciamento de dados Distribuição Requisitos Regras de negócio Controle de concorrência Engenharia de requisitos 13 Sérgio Castelo Branco Soares Passo 2: Implementar o sistema, separando os interesses Alguns concerns são bem modelados como objetos (núcleo do sistema) Passo 3: Recompor o sistema classes e interfaces • interface com o usuário • regras de negócio 14 Sérgio Castelo Branco Soares Outros (crosscutting concerns) como aspectos aspects and tipos auxiliares W E A V E R Sistema executável • distribuição, controle de concorrência, armazenamento de dados 15 Sérgio Castelo Branco Soares Desenvolvimento de Software Orientado a Aspectos Identificador de concerns Interesses OOP Requisitos AOP Classes Interfaces Aspects W E A V E R 16 Sérgio Castelo Branco Soares OOP vs AOP Sistema executável Requisitos funcionais Controle de concorrência Requisitos funcionais Controle de concorrência Gerenciamento de dados Distribuição Interface com o usuário Gerenciamento de dados Distribuição Interface com o usuário Sérgio Castelo Branco Soares 17 Sérgio Castelo Branco Soares 18 3 Composição nos pontos junção (join points) Combinação (weaving) é usada para … Compor o “núcleo” do sistema com os aspectos Sistema original chamadas locais entre A e B A B Processo de combinação Sistema distribuído chamadas remotas entre A e B Sérgio Castelo Branco Soares um método é chamado e retorna ou lança uma exceção object B dispatch um método executa e retorna ou lança uma exceção A B Protocolo de distribução 19 Comportamento pode ser alterado nos pontos de junção… um método executa e retorna ou lança uma exceção Fonte: AspectJ Tutorial 20 aspectj.org Sérgio Castelo Branco Soares AspectJ: identificando chamadas de métodos da fachada (servidor) Identifica pontos de junção de um sistema identifica código dentro da classe ... • chamadas e execuções de métodos (e construtores) • acessos a atributos • tratamento de exceções • inicialização estática e dinâmica dispatch Weaver Conjunto de pontos de junção (pointcut) Um método é chamado e retorna ou lança uma exceção object A Aspectos de distribuição de nome do conjunto de pontos de junção pointcut facadeMethodsCall(): within(HttpServlet+) && Expõe o contexto nos join points call(* IFacade+.*(..)); —argumentos de métodos, objetos alvo, atributos Composição de pontos de junção • &&, || e ! Sérgio Castelo Branco Soares 21 Comportamento transversal (advice) qualquer método com quaisquer argumentos Sérgio Castelo Branco Soares 22 AspectJ: antes (before) de chamar métodos da fachada private IFacade remoteFacade; Define código adicional que deve ser executado… before(): facadeMethodsCall() { getRemoteInstance(); • before • after } synchronized void getRemoteInstance() {... —after returning —after throwing remoteFacade = • ou around (IFacade) java.rmi.Naming.lookup(...); pontos de junção Sérgio Castelo Branco Soares identifica chamadas de … ...} 23 Sérgio Castelo Branco Soares 24 4 Além de mudanças (dinâmicas) com comportamento transversal… AspectJ: transformando chamadas locais em remotas void around(Complaint c) throws Ex1,…: facadeMethodsCall() && args(c) && call(void update(Complaint)) { try { remoteFacade.update(c); AspectJ suporta mudanças estáticas • alterar relação de subtipo • adicionar membros a classes obtendo e utilizando argumento de método em um ponto de junção } catch (RemoteException rmiEx) {...} Declarações intertipos } 25 Sérgio Castelo Branco Soares Sérgio Castelo Branco Soares AspectJ: mudanças estáticas Mais construtores de AspectJ declare parents: HealthWatcherFacade implements IFacade; } catch ... Adicionando o método main na classe fachada 27 Sérgio Castelo Branco Soares cflow(<conjunto de junção>) • Identifica pontos de junção que estejam no fluxo de execução identificado por <conjunto de junção> public aspect DistributionAspect { declare parents: ... get(<assinatura>) / set(<assinatura>) private IFacade remoteFacade; public static void HealthWatcherFacade.main(String[] as)... pointcut facadeMethodsCall(): ... before(): facadeMethodsCall() ... private synchronized void getRemoteInstance() ... void around(Complaint complaint) ... • Leitura/atribuição a atributos declare soft: <nome do tipo> : <conjunto de junção>; • A exceção <nome do tipo> será encapsulada em uma exceção não checada em tempo de compilação (runtime) em qualquer ponto de junção definido por <conjunto de junção> Sérgio Castelo Branco Soares 28 Aspecto de distribuição em AspectJ Mais construtores de AspectJ withincode(<assinatura de método>) • Identifica pontos de junção cujo código em execução pertence ao corpo do método ou construtor especificado por <assinatura de método> Alterando a hierarquia de tipos } Sérgio Castelo Branco Soares this(<nome do tipo>) • Identifica pontos de junção cujo objeto em execução é uma instância de <nome do tipo> public static void HealthWatcherFacade.main(String[] args){ java.rmi.Naming.rebind("/HW"); target(<nome do tipo>) • Identifica pontos de junção onde o objeto alvo é uma instância de <nome do tipo> declare parents: Complaint || Person implements java.io.Serializable; try {... 26 } 29 Sérgio Castelo Branco Soares 30 5 Aspectos de desenvolvimento: debugging simples com AspectJ AspectJ: pontos positivos public aspect DatabaseDebugging { pointcut queryExecution(String sql): call(* Statement.*(String)) && args(sql); • debugging before(String sql): queryExecution(sql) { System.out.println(sql); } } Sérgio Castelo Branco Soares 31 Novo paradigma Projeto da linguagem • tratamento de exceções • conflitos entre aspectos Requer suporte de ferramentas Combinação (apenas) estática Sérgio Castelo Branco Soares 32 Referências • relação entre classes e aspectos deve ser minimizada • inconsciência (obliviousness) Produtividade Permite implementação e testes progressivos Sérgio Castelo Branco Soares AspectJ: pontos negativos Modularidade, reuso, e extensibilidade de software Inconsciência (obliviousness) Suporte a desenvolvimento com IDEs 33 Gregor Kiczales et. al. Aspect-Oriented Programming. European Conference on Object-Oriented Programming, ECOOP'97 http://groups.yahoo.com/group/asoc-br/ http://www.aosd.net/ http://www.eclipse.org/aspectj Sérgio Castelo Branco Soares 34 Cross References view Mostra relacionamentos de e para o membro selecionado Um clique duplo do mouse sobre uma das extremidades abre e mostra o arquivo fonte no editor Classe Aspecto Sérgio Castelo Branco Soares 35 Sérgio Castelo Branco Soares 36 6 Impacto de Crosscutting Ex: Logging no Apache Tomcat Visualizador de aspectos: mostra o impacto de crosscutting dos aspectos de um projeto, pacote ou classe 37 Sérgio Castelo Branco Soares Linhas vermelhas: logging • não estão no mesmo lugar • nem mesmo em poucos lugares Sérgio Castelo Branco Soares 38 Software Productivity Group http://spg.dsc.upe.br/ UPE e UFPE Sérgio Castelo Branco Soares Sérgio Soares [email protected] 39 7