lidando com java obsoleto: do struts 1.0 ao cdi
TRANSCRIPT
Lidando com Java Obsoleto: Do Struts 1.0
ao CDIJava na Crista da Onda
Lidando com Java Obsoleto: Do Struts 1.0
ao VRaptor com CDIJava na Crista da Onda
David [email protected]
linkedin.com/in/davidrobert
Lidando com Java Obsoleto
Struts & CDI
AMBIENTE
A long time ago in a galaxy far,
far away...
AMBIENTE
ManutenabilidadeComprometida
❏ baixa coesão❏ alto acoplamento❏ código legado
JDBC> 600 conexõespor requisição
ManutenabilidadeComprometida
❏ baixa coesão❏ alto acoplamento❏ código legado
Como melhorar?
AMBIENTE
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
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?
conexões
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();
}
public class ConnectionContainer { private Connection connection;
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);
}
Podemos usar com injeção?
conexões
@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!
decoratorsstereotypesinjection pointscustom scopes conversation scope extensions
???
Qual framework adotar?
Como escolher?
JSFPlay!
SpringVRaptor
???
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
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!