Experiência AngularJS + Java em Produção

divedoo

Olá Pessoal,

O post de hoje vou falar  um pouco sobre a experiência que tivemos aqui na ITSLabs com desenvolvimento de um produto usando AngularJS e hoje está em produção. O produto ainda é um MVP versão 1.0.0 e foi de desenvolvido em 45-50 dias.  Para quem acompanha o blog venho trabalhando com AngularJS no dia a dia a quase 1 ano e criei o grupo AngularJS-Brazil (https://groups.google.com/forum/#!forum/angularjs-brazil) no Google Groups e mais uma vez reforço para quem está chegando, quer aprender qualquer tecnologia? Saia do CRUD, só assim você vai poder aprender  de verdade.

Lets go…

 

ITSLabs

Antes de começar falando do projeto, deixa eu falar rapidamente da ITS. A ITS é uma start-up  voltada para criação de produtos web e mobile. Aqui buscamos resolver os problemas dos nossos clientes identificamos qual a tecnologia resolve melhor o problema. Portanto, a tecnologia nada mais é que apenas uma ferramenta para atingir o objetivo. Hoje temos projeto com AngularJS, NodeJS, Java etc.  Em breve assim que tiver um ok do cliente teremos mais um case que vou compartilhar aqui com vocês de um projeto NodeJS + AngularJS.  A ITSLabs não é consultoria, fabrica de software que tem o foco apenas em desenvolver software, vamos um pouco além, e precisamos entregar valor ao negócio do cliente e também trazer valor para nossa equipe técnica. Já rejeitamos projetos que financeiramente seria ótimo, mas valor entregue tecnicamente para nossa equipe seria quase zero. Nosso dia a dia é bem Agile, trabalhamos 95% remoto e pouco focado em horas trabalhadas ou que horas você entrou hoje e saiu ontem. Atender aos prazos com qualidade é o nosso maior ativo.

 

DiveDoo – www.divedoo.com

É uma plataforma que busca resolver o problema de quem  busca acessório, curso, equipamentos na área de mergulho, mas não sabe como e onde encontrar. Fazendo uma pesquisa no Google as informações estão espalhadas e alguns sites podem não ser confiáveis. Baseado nisso foi criado a plataforma pela mergulhadora Gabriela Galvão.

Nossa experiência com AngularJS          

Esse foi  o nosso terceiro projeto com AngularJS em produção, os dos primeiros eram projetos bem menores com relação ao DiveDoo.  Ter escolhido AngularJS foi  uma excelente escolha, por alguns motivos:

  • Manutenção do lado do cliente: ganhamos muito na organização de  js, css etc.  Isso foi fantástico e crucial  para o desenvolvimento;
  • Integração com back-end: ter o back-end e front 100% independente. É fantástico, podemos mudar para  qualquer outra tecnologia sem precisar tocar no código do cliente.
  • Ter programadores trabalhando em paralelo e separado sem bloqueios: isso ajudou bastante, alguns programadores back-end odeiam front-end (eu era um desses, mas deixei de ser graças ao AngularJS) e aqui podemos manter cada um trabalhando do seu lado e se comunicando apenas através de uma API REST.
  • IE: esse cara é uma dor de cabeça. Então se você pensa em querer dá suporte para versões antigas  como 8 ou inferior. Esquece de usar AngularJS, apesar que o pessoal da Google fala nas versões mais antigas do AngularJS que eles oferecem suporte e talz, algumas coisas não funcionam bem, e ainda depender do Windows com a versão do IE, pegamos incompatibilidade. É tenso o negócio, simplesmente consome um tempo enorme para tentar achar a solução e se encontrar.  Se você tem um projeto que vai dá suporte a esse camarada em versões antiga, pode ir buscando outro framework, pq o AngularJS não vai rolar. E o problema não é do AngularJS, na verdade ele nasceu sem vontade nenhuma em querer ajudar o browser da Microsoft :). A partir do IE9 as coisas já funcionam com uma compatibilidade melhor.

Tools

Usar Yeoman  & Grunt é um fator de produtividade. Criamos uma estrutura do lado do back-end onde o desenvolver front-end consegue testar aplicação com back-end localmente e podendo sempre pegar o ultimo código que foi comitado. Separamos isso em módulos :

  • Web: aqui  é a versão que vai para o servidor remoto
  • Core: todo back-end
  • Webdev: aqui é onde o programador front-end trabalha e segue toda a estrutura do Yeoman. Se for preciso debugar um código local basta subir aplicação a partir desse modulo  usando o comando: grunt Server  e pronto.O Server vai subir em porta e IP diferente da aplicação que possui o back-end.  Quando o trabalho de front-end está concluído e precisa ser integrado com o back-end basta executar um grunt build e todo código do front é minificado e colocado no modulo de web  para ser deployed. Para quem está trabalhando no front-end isso é transparente.

Montamos essa estrutura, pois em projetos passados sofremos bastante com isso, a estrutura tudo em um único projeto funciona bem, quando temos um projeto que não é grande, ou seja, poucas funcionalidades. 

Aprendizado

Aprendemos que sem Yeoman é querer sofrer. Realmente é uma ferramenta poderosa e querer fazer tudo na mão, é perda de tempo, exceto se você está querendo aprender criando seus projetos house made. Mas, projeto que vai para produção, não recomendo. UI-Router  esse é o cara. Muito bom, e facilita bem o uso de rotas dentro do AngularJS. Quando você usa o UI-router que percebe a limitação que temos com as rotas default com AngularJS. Em breve vou fazer um post sobre  ele. Aprenda a separar as coisas, controller, services etc. Ter tudo organizado e separado é importante. Crie padrões de nomeação de arquivos para facilitar na hora que for buscar. Se você usa o Yeoman, ele ajuda em manter tudo organizado.  Use e abuse da injection dependecy que temos no angularJS, é fantástico. Lembro que quando comecei a estudar AngularJS demorei um pouco para pegar o core de usar injeção de dependência , a dica é leve o tempo que puder estudando, mas aprenda.  Não tenha medo de perguntar e não ache que você sabe tudo, esse é o maior erro achar porque fez algum CRUD que já aprendeu, pelo contrario é nesse momento que a brincadeira começa, todo dia  você vai aprender alguma coisa nova.

Conclusão

Hoje usamos fortemente AngularJS em nossos projetos aqui na ITS, há outros valores na tecnologia da Google que se fosse entrar nos detalhes  o post viraria um livro. Por falara nisso, em breve estarei lançando meu próximo livro que será sobre AngularJS, que nada mais vai ser o que aprendi nesse  quase 1 ano em três projetos completamente diferente e os erros que cometi, e acertos que também tive.

Vou ficando por aqui…

See ya!!!Abraços,

Série Dropbox: Enviando arquivos para o Dropbox via Java Application

 
Olá Pessoal, 
 
Venho trabalhando há um bom tempo com API do Dropbox em web apps. No post de hoje vamos ver como enviar um arquivo para uma conta no dropbox via Java Application. É um verdadeiro upload via console. 
 
Lets go…
 
O cenário
 
Imagine que você queira ter um upload na sua aplicação. Nada de diferente aqui, mas sabemos que há várias formas de fazer isso e temos bastante frameworks Java que nos ajudam. Mas, como fazer de forma rápida e segura? Aqui usamos o serviço do Dropbox para armazenamento de arquivos que vem da aplicação. Isso nos ajuda em vários pontos:
 
1. Segurança: Certamente o time do dropbox é preocupado com isso;
 
2. Histórico: Por default o dropbox mantém um histórico do arquivo, então em caso de precisar retornar uma versão é muito simples; 
 
 
3. Baixo custo de desenvolvimento: API do dropbox é bem documentada e tem suporte a diversas linguagens. O que teremos que fazer é sempre implementar algo muito específico ou encapsular algumas features mais comuns para evitar de ter código repetido em várias partes da aplicação; 
 
Ai nasceu no laboratorio da ITS a easyJavaDropboxAPI, que nos ajuda no dia a dia. A API ainda está nas primeiras versões e recentemente acabou de sair a versão 1.1.0 com algumas funcionalidades e melhorias e uma delas é permitir salvar arquivos no dropbox (a versão anterior nos permitia apenas ler um arquivo). O método na API que salva um arquivo é assim:
 
public void saveToDropbox(String finalName,InputStream inputStreamContent) throws DbxException,IOException;

 

Vamos ver na prática 
 
 
Metendo a mão na massa  
 
Primeiro Passo
 
Vamos usar o projeto easyJavaDropboxAPIExample que vimos no post:
 
Então você precisa ter feito os passos descritos no post acima.
 
Segundo Passo
 
Se fez o passo 1, certamente consegue listar os arquivos. 
 
Terceiro Passo
 
Atualize o pom.xml para usar a versão mais nova da API:
 
<dependencies>
<dependency>
<groupId>com.its.api</groupId>
<artifactId>easyJavaDropboxAPI</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>

 

Quarto Passo 
 
Agora vamos adicionar o código que fará o upload. Não vamos modificar o código existente, apenas adicionar. No método main adicone as seguintes linhas:
 
//upload service
EasyJavaDropBoxServiceImpl upload = new EasyJavaDropBoxServiceImpl(token);
saveToDropbox(upload);

O código com o método main completo ficou assim: 

public static void main(String[] args) throws DbxException, IOException {
String token = "your token here";
String path = "/";
EasyJavaDropBoxService easyJavaDropBoxService = new EasyJavaDropBoxServiceImpl(path, token);
List<DbxEntry> listFiles = easyJavaDropBoxService.listFiles();
for (DbxEntry file : listFiles) {
System.out.println(file.name);
}
//upload service
EasyJavaDropBoxServiceImpl upload = new EasyJavaDropBoxServiceImpl(token);
saveToDropbox(upload);
}

Lembre-se de que é preciso gerar o token para sua conta. Quando tiver o token coloque como valor na variável token. Agora vamos criar o método que salva o arquivo no dropbox:

  

private static void saveToDropbox(EasyJavaDropBoxService uploadEasyJavaDropBoxService) throws DbxException, IOException {
//creating new file
File file = new File("camilotestedropbox2.txt");
file.createNewFile();
//writing content in file
FileWriter fileWriter = new FileWriter(file);
fileWriter.write("Test upload to dropbox  api");
fileWriter.close();

try {
FileInputStream fileInputStream = new FileInputStream(file);
String fileName = file.toString();
//calling method from easyJavaDropboxAPI
uploadEasyJavaDropBoxService.saveToDropbox(fileName, fileInputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
}

}

Testando 

Agora chegou a hora de testar. Rode a aplicação e vamos ver a saída no console: 
 
dropboxuploadconsole
 
Na imagem acima são listados os arquivos que tenho no meu dropbox. Agora vamos ver se no dropbox tem o novo arquivo que criei: 
 
dropboxfileuploadeddone
 
Pronto, arquivo enviado para o dropbox. Simples, não? 
 
O projeto foi atualizado no Github:
 
 
Vou ficando por aqui. Espero que tenham gostado do post. 
 
Abracos, see ya!!!

Série Dropbox: Por que usar easyJavaDropboxAPI?

Olá Pessoal, 
 
Hoje vou falar rapidinho sobre a easyJavaDropbox API. Recebi um e-mail recentemente de um leitor perguntando por que ele deveria usar a easyJavaDropboxAPI já que pode usar diretamente API do dropbox. 
 
Lets go… 
 
 
Por que usar easyJavaDropboxAPI? 
 
A motivação com que criei a easyJavaDropboxAPI foi para encapsular algumas funcionalidades da API do dropbox. Se você usa muito recurso da API vai ver que tende a criar código repetido ou terá que criar uma classe utilitária para tratar e evitar código repetido. Ao invés de criarmos uma classe utilitária, que tal uma API que pudesse ser usada em outros projetos? Assim nasceu a easyJavaDropboxAPI. 
 
A API ainda está em uma fase bem inicial e simples. Estamos já com a pre-release da versão 1.2.0 e vamos atualizando constatemente à medida que identificamos novas funcionalidades que seria interessante na API e que deveria ser encapsulada. 
 
Quando devo usar? 
 
– Se precisa salvar um arquivo no dropbox via upload temos um método que resolve isso facilmente; 
– Se precisa listar e obter arquivos que estão no dropbox; 
– Se quer pesquisar um arquivo no dropbox, temos essa funcionalidade já implementada; 
  
Ainda temos poucas funcionalidades, na verdade todas elas foram nascendo com cases reais de projetos, e vamos evoluindo a API dessa maneira, pegando requisitos de mercado e melhorando.
 
Conclusão 
 
Se você quer uma forma mais simples de se conectar com o dropbox, a easyJavaDropbox API vai te ajudar evitando escrever mais código do que precisa. Uma outra vantagem que ganhamos foi de separar o código de terceiros do nosso código de negócio, pois apesar de usarmos as funcionalidades do dropbox para resolver problemas de negócio queríamos manter o código separado porque se amanhã deixarmos de usar o serviço do dropbox, o que iremos fazer? Então mantivemos isso separado usando a API e a troca do dropbox por um outro serviço, seja de terceiro ou próprio. É simples, fácil e com um custo de manutenção aceitável. Nada de big refactoring :). 
 
Github do Projeto
 
 
Vou ficando por aqui, e não deixe de mandar sugestões, críticas etc.

Implementando UserDetailsService Spring Security

 

Olá Pessoal,

No post de hoje veremos como implementar a interface UserDetailsService do Spring. Mas para que serve ela, Camilo? É o que vamos ver logo a seguir…

Lets go…

Starting…

Este post será bem pontual e vou considerar que você já usa e conhece o Spring Security. Uma das opções mais comum de validar autenticação do usuário seria algo mais ou menos assim:

<jdbc-user-service data-source-ref="dataSource"

users-by-username-query="SELECT email, password, 'true' as enable FROM user WHERE email=?;"

authorities-by-username-query="select distinct u.email,ro.role_description from user u, user_role r, role ro where u.id = r.role_id and ro.id=r.role_id and u.email=?;" />

 

Independente de como está seu relacionamento no banco, a questão é que você usaria o jdbc-user-service />

Mas você pode estar perguntando “e se quiser usar minha classe de serviço (service) ou meu DAO, se nessas classes eu já tenha a implementação de busca de um usuário, como fazer?”.

Implementando UserDetailsService

Por default, o Spring a implementa. O que vamos fazer é  um override dessa implementação e dizer que é pra chamar um serviço de busca customizado.

Vou mostrar a seguir apenas o código principal e o que você precisa fazer.  Será bem pontual.

Step 1

Crie uma classe para esse tratamento (chamei de AuthenticationService). Veja :

@Service

public class AuthenticationService implements UserDetailsService {

       @Autowired

       @Qualifier("userServiceImpl")

       private UserService userServiceImpl;      

       @Override

       public UserDetails loadUserByUsername(String email)   throws UsernameNotFoundException, DataAccessException {

List<GrantedAuthority> listGrantAuthority = new ArrayList<GrantedAuthority>();

                    User user = userServiceImpl.getByEmail(email);

                    checkGrantAuthorities(user, listGrantAuthority);

                    UserDetails userDetails = validateUser(email, listGrantAuthority,user);

             return userDetails;

       }

 

O método que vamos trabalhar não é difícil de saber, já que tem anotação @Override. É nele que vamos realizar a busca usando as classes de serviço que chama o DAO. No caso acima o username é o email do usuário, por isso realizo a busca por email.  O método checkGrantAuthorities(…) verifica a role do usuário e adiciona em uma lista de Grant:

private void checkGrantAuthorities(User user, List<GrantedAuthority> listGrantAuthority) {

if(user!=null && user.getRoles()!=null && user.getRoles().isEmpty()==false)

             for(Role roleUser : user.getRoles()){

                    final String PREFIX = "ROLE_";

                    String role = PREFIX + roleUser.getRoleDescription();

                    listGrantAuthority.add(new GrantedAuthorityImpl(role));    

             }

       }

 

Precisamos fazer isso para que o Spring Security possa validar se o usuário passado possui Role de permissão para a página que deseja. O PREFIX que criamos é que no BD você não salva ROLE_ADMIN, daí precisamos fazer isso. Caso já salve como prefixo, você deve remover essa concatenação do código. Uma vantagem de não salvar o prefixo é que se amanhã você mudar de framework que faça essa parte de segurança, terá que fazer update em todo banco. Então é melhor deixar a aplicação tratar isso para seu banco ficar transparente.

Em seguida criei um método que valida se o usuário retornado é válido:

private UserDetails validateUser(String email,List<GrantedAuthority> listGrantAuthority, User user) {

             UserDetails userDetails= null;

             if(user!=null){

                    boolean accountNonLocked=true;

                    boolean enabledUser=true;

                    boolean accountNonExpired=true;

                    boolean credentialsNonExpired=true;

userDetails = new  org.springframework.security.core.userdetails.User(email, user.getPassword(), enabledUser, accountNonExpired, credentialsNonExpired, accountNonLocked, listGrantAuthority);

              }     

             return userDetails;

       }

 

 

Eu tive que colocar o caminho completo do User referente ao Spring  devido já ter um import para minha classe User.

Altere o arquivo de contexto do SpringSecurity. No meu caso, tenho um arquivo XML chamado de springsecurity.xml e no authenticationManager preciso dizer como vamos validar o usuário. Para usar a implementação acima precisamos dizer isso:

 

<authentication-manager alias="authenticationManager">

       <authentication-provider user-service-ref="authenticationService">      

             </authentication-provider>

       </authentication-manager>

 

Pronto. Feito isso, agora basta testar sua aplicação e ver que vai funcionar da mesma forma que o jdbc default, porém agora os dados vem de um serviço de pesquisa que você implementou, que pode ser em HQL, Criteria etc.

A documentação do Spring é muito bacana:

http://docs.spring.io/spring-security/site/docs/3.1.4.RELEASE/reference/ns-config.html

Abraços. Vou ficando por aqui e espero que tenham gostado

See ya!!

Automatizando seu DB com FlyWay Plugin – MySql

Olá Pessoal,

No post de hoje vou mostrar para vocês como podemos automatizar a criação de um banco de dados usando o plugin flyway. Aqui na ITS temos usado o plugin para aumentar a produtividade e sempre manter a integridade dos ambientes.

Lets go…

O problema

Há várias ferramentas e formas de automatizar a criação das tabelas do banco com cenários já prontos ou até vazios.  Aqui na ITS, para os projetos Java temos usado o flyway, apesar de que testamos outras como o DBMaintain, mas optamos pelo plugin flyway, já que em termos de resultado final era semelhante ao dbmaintain, porém a curva de aprendizado e configuração  era mais rápida.  Para projetos Ruby, estamos vendo outra solução.

O problema que tínhamos aqui era a criação da base de dados para cada ambiente, desde local até ambiente de INT, DEV e PROD. A modelagem do banco pode mudar (e certamente vai) e quando isso acontece, o problema está feito. Como atualizar cada ambiente rapidamente?

Opção 1

Criar um dump do banco e rodar o .sql em cada ambiente manualmente.

Opção 2

Automatizar esse processo de update.

Nesse post vamos nos limitar apenas em como gerar a base de dados rapidamente. Em outro post veremos como atualizar outros ambientes através de uma ferramenta de build continuous como o Jenkins. 

A opção 1 funciona, mas não é a ideal, pois é preciso logar em cada ambiente e rodar o .sql. Isso consome tempo e é chato de fazer, ninguém gosta de fazer esse trabalho repetitivo. E se o banco durante o dia mudar 3 ou 4 vezes? Quantas vezes você vai executar a opção 1? Se você tem 3 ambientes para atualizar será preciso fazer isso 3 vezes a cada mudança. Péssimo, não? 

A opção 2

Você pode automatizar. Há ferramentas que ajudam a fazer isso usando um Servidor de Build como o Jenkins ou até como plugin maven.  Já usei o dbmaintain, mas analisando outras opções encontrei o flyway, até porque o desenvolvedor pode rodar o plugin local e se tiver o banco de dados rodando em segundos ele tem o ambiente local atualizado.

Configurando o FlyWay  via Maven

Antes de tudo você precisa ter um arquivo .sql que irá criar as tabelas e ele deve estar nessa estrutura: src/main/resources/db/migration

flywaysql

E o nome do arquivo tem que ser V1__QUALQUERNOME.sql

São 2 underscore. Se seu banco mudou você precisa ter um V2 e assim por diante. O flyway faz um tracking disso e salva em uma tabela schema_version. Se você tem mais de um ambiente, sugiro dar uma lida nesse post:

http://lwandersonmusings.blogspot.com/2012/07/using-maven-to-integrate-flyway.html

Vamos ver na prática um simples exemplo. Vou considerar que você já tem um projeto Maven

Step 1

Abra o pom e adicione:

<plugin>

                           <groupId>com.googlecode.flyway</groupId>

                           <artifactId>flyway-maven-plugin</artifactId>

                           <version>2.2.1</version>

                           <configuration>

                                  <url>jdbc:mysql://localhost:3306/seu_database</url>

                                  <user>camilo </user>

                                  <password>2014</password>

                           </configuration>

                           <dependencies>

                                  <dependency>

                                        <groupId>mysql</groupId>

                                  <artifactId>mysql-connector-java</artifactId>

                                        <version>5.1.25</version>

                                  </dependency>

                           </dependencies>

                    </plugin>

 

 Step 2

Garanta que o banco foi inicializado.

Step 3

Garanta que o database exista, caso contrário o flyway não vai conseguir conectar.

flywaydatabase

Step 4

via command line (se preferir pode usar o Eclipse) digite o seguinte comando:

flywaycommandmigrate

Step 5

Veja o resultado:

flywaycommandmigrateresult

 

flywaytablecreated

Observe que as tabelas foram criadas. Tive que ocultar os nomes das tabelas. 

Simples não?

Alguns comandos básicos

mvn flyway:clean

 

Limpar o Database, ou seja, todas tables são apagadas.

mvn flyway:info

 

Mostra quando o último script foi rodado e o status.

mvn flyway:migrate

 

Faz a migração, ou melhor, executa o .sql em si.

Note: Você pode usar o recurso de profiles e ter diferentes execuções para o flyway.

O flyway tem se mostrado um plugin muito bom no dia a dia e atendendo aos requisitos que precisamos, sem falar que tem uma boa documentação e os posts no blog deles tem sido bem mão na massa. 

Abraços, see ya!!