Lidando com Java Obsoleto: Do Struts 1.0 ao CDI Java na Crista da Onda Lidando com Java Obsoleto: Do Struts 1.0 ao VRaptor com CDI Java na Crista da Onda David Robert [email protected] linkedin.com/in/davidrobert Lidando com Java Obsoleto Struts & CDI AMBIENTE AMBIENTE A long time ago in a galaxy far, far away... Manutenabilidade Comprometida ❏ baixa coesão ❏ alto acoplamento ❏ código legado JDBC > 600 conexões por requisição Manutenabilidade Comprometida ❏ baixa coesão ❏ alto acoplamento ❏ código legado AMBIENTE Como melhorar? Reescrever ? Reescrever ? ➢ ~ 700.000 linhas de código (>200.000 de Java) Reescrever ? ➢ ~ 700.000 linhas de código (>200.000 de Java) ➢ O que fazer com as regras de negocio? reescrever? Reescrever ? ➢ ~ 700.000 linhas de código (>200.000 de Java) ➢ O que fazer com as regras de negocio? reescrever? ➢ Quanto tempo vai custar? O beneficio vale a pena? Como evoluir de maneira saudável? Como evoluir de maneira saudável? Baixo acoplamento Alta Coesão Testes! CDI public class ProdutoDao { public void salvar(Produto produto) { entityManager.persist(produto); } } public class ProdutoDao { private EntityManager entityManager; public ProdutoDao(EntityManager em) { this.entityManager = em; } public void salvar(Produto produto) { entityManager.persist(produto); } } public class ProdutoDao { private EntityManager entityManager; // recebe a dependência pronta public ProdutoDao(EntityManager em) { this.entityManager = em; } // usa a dependência public void salvar(Produto produto) { entityManager.persist(produto); } } injeção de dependências! inversão de controle injeção de dependências! separação de responsabilidades inversão de controle injeção de dependências! CDI public class ProdutoDao { private EntityManager entityManager; public ProdutoDao(EntityManager em) { this.entityManager = em; } public void salvar(Produto produto) { entityManager.persist(produto); } } public class ProdutoDao { private EntityManager entityManager; @Inject public ProdutoDao(EntityManager em) { this.entityManager = em; } public void salvar(Produto produto) { entityManager.persist(produto); } } public class ProdutoDao { @Inject private EntityManager entityManager; public void salvar(Produto produto) { entityManager.persist(produto); } } @Inject injeção de dependências! Injeção de dependências por si só já é uma baita diminuição de acoplamento Injeção de dependências por si só já é uma baita diminuição de acoplamento Mas, se pensar bem, ainda estamos bem acoplados com a dependência que recebemos conexões E se existirem JSPs que são acessados diretamente e abrem conexão com o banco? conexões Quando criar a conexão? conexões Podemos usar um filtro? conexões Lazy? public static ConnectionContainer putContainerInRequest(HttpServletRequest request) { ConnectionContainer container = new ConnectionContainer(); request.setAttribute(ConnectionFactory. OPEN_IN_VIEW_CONNECTION_CONTAINER, container); return container; } public static Connection getConnectionFromRequest(HttpServletRequest request) { ConnectionContainer con = (ConnectionContainer)request.getAttribute( OPEN_IN_VIEW_CONNECTION_CONTAINER); return con.getConnection(); } ConnectionContainer { private Connection connection; public class public Connection getConnection() { if (connection == null) { try { connection = ConnectionFactory.createNewConnection(); } catch (SQLException e) { logError("Error blah", e); } } return connection; } } public Connection getCon(HttpServletRequest request) throws SQLException { return getConnectionFromRequest(request); } @RequestScoped public Connection getCon(HttpServletRequest request) throws SQLException { return getConnectionFromRequest(request); } conexões Podemos usar com injeção? @Produces @RequestScoped public Connection getCon(HttpServletRequest request) throws SQLException { return getConnectionFromRequest(request); } Utilizando esse mesmo conceito no EntityManaget public class JPAUtil { @Produces @ApplicationScoped public EntityManagerFactory criaFactory() { return Persistence.createEntityManagerFactory("jpa"); } @Produces @RequestScoped public EntityManager criaEM(EntityManagerFactory factory){ return factory.createEntityManager(); } } @produces métodos produtores! login <filter> <init-param> <param-name>restrictedUrl</param-name> <param-value> /sellerOrder.do, /buyerOrder.do, /clientCategory.do, /clientCreate.do, /clientEdit.do, /clientSearch.do, /productCreate.do, ... </param-value> </init-param> <init-param> <param-name>restrictedCommands</param-name> <param-value> showUserPasswordForm, showOrderHistoryForm, showUserFeedbackEditForm, showUserShopForm, showUserBannerForm, showUserPictureForm, showUserContactInfoForm, ... </param-value> </init-param> </filter> Dificuldade de manutenção @InterceptorBinding @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface BlockUnloggedUsers { } @InterceptorBinding @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface BlockUnloggedUsers { } @BlockUnloggedUsers public class ProductSearchAction { /* ... */ } @InterceptorBinding @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface BlockUnloggedUsers { } @BlockUnloggedUsers public class ProductSearchAction { /* ... */ } Bem Melhor! Como testar ? public class BlockedActionsTest { private Class<?>[] blackListed = new Class<?>[]{ BuyerOrderAction.class, ClientCreateAction.class, ... }; @Test public void shouldVerifyBlackListedActions(){ for (Class<?> blockedAction : blackListed){ assertNotNull( blockedAction.getAnnotation( BlockUnloggedUsers.class)); ... ... Method[] actionMethods = blockedAction.getMethods(); for (Method method : actionMethods) { assertNull( method.getAnnotation( UnloggedUsers.class)); } } @InterceptorBinding interceptadores! login login public void loginIntoSession(LoginAuthentication loginAuthentication, HttpServletRequest request, HttpServletResponse response) { UserInfo loginUser = login.login(loginAuthentication); SessionUtils.putIntoSession(request,loginUser); SessionUtils.setLoggedUser(request, loginUser); // + Código para merge dos carrinhos // + Código de traqueamento // = Código Monstro! } public void loginIntoSession(LoginAuthentication loginAuthentication, HttpServletRequest request, HttpServletResponse response) { UserInfo loginUser = login.login(loginAuthentication); SessionUtils.putIntoSession(request,loginUser); SessionUtils.setLoggedUser(request, loginUser); sessionLoginEvent.fire( new SessionLogin( loginUser, request, response)); } @Inject private Event<SessionLogin> sessionLoginEvent; public void algumMetodoInteressado( @Observers SessionLogin sessionLogin) { // ... } @Observers eventos! Isso não é tudo! decorators stereotypes injection points custom scopes conversation scope extensions ??? Qual framework adotar? Como escolher? JSF Play! Spring VRaptor ??? Quão fácil é trocar um framework? ❏ Desenvolvedores não envolvidos no processo? Quão fácil é trocar um framework? ❏ Desenvolvedores não envolvidos no processo? ❏ Entregas de produto? Quão fácil é trocar um framework? ❏ Desenvolvedores não envolvidos no processo? ❏ Entregas de produto? ❏ Ferias coletivas? Neste caso trocar é blocante! Se já é difícil lidar com um só, imagine dois! Se já é difícil lidar com um só, imagine dois! if (analyser.isRouteToVRaptor((HttpServletRequest) req)) { super.doFilter(req, res, chain); } else { Elo7MutableRequest mutableRequest = new Elo7MutableRequest((HttpServletRequest) req); Elo7MutableResponse mutableResponse = new Elo7MutableResponse((HttpServletResponse) res); StrutsRequestStarted request = new StrutsRequestStarted(chain, mutableRequest, mutableResponse); strutsRequestStartedEvent.fire(request); chain.doFilter(req, res); } Você deveria usar CDI em todos os seus projetos Java! Considere usar VRaptor em seus projetos Obrigado! David Robert @while42 Links adicionais ❏ Elo7 ❏ Curso de Arquitetura Java ❏ Diminua suas dependências com os eventos do CDI ❏ Porque você deveria usar CDI nos seus projetos Java!