Simplificando integrações com Apache Camel
Hoje em dia umas das maiores preocupações que temos é desenvolver um processo de integração simples e funcional. Como isso é possível?
Poucos dias atrás me deparei com um problema de precisar ler um email Pop3 ou Imap e capturar todos os anexos do tipo XML e jogar para um determinado diretório.
Comecei a tentar montar uma própria arquitetura pra isso, porém como não gosto de reinventar a roda. Fiz uma breve pesquisa em busca de padrões de integração e encontrei um poderoso framework conhecido por Apache Camel e ele tem suporte a maioria dos padrões de intregação existentes no livro Enterprise Integration Patterns.
O Camel possui vários componentes para integração e por sorte ele tem um compontente para envio e recebimento de emails\o/
Bem então vamos colocar as mãos na massa hehehe
O que eu preciso é Ler anexos de um Determinado email separar tudo o que é arquivo XML e disponibilizar em um diretório especifico.
Nesse caso irei usar 2 componentes.
1º – Camel mail ( para ler os anexos )
2º – Camel file ( para salvar os arquivos no dirétorio)
O Camel possui uma DSL ( Domain Specific Language) que facilita a criação de rotas usadas na integração sem necessitar de arquivos XML.
Então para fazer todo esse processo ficaria assim usando o camel:
CamelContext camelContext = new DefaultCamelContext();
// Adiciona as rotas ao contexto
camelContext.addRoutes( camelContext.addRoutes(new RouteBuilder() {
@Override
public void configure() throws Exception {
from("pop3://servidor?username=cristiano&password=senha&delete=true&consumer.delay=3000").process(new MyMailProcessor())
.split(body()).to("file:/home/cristiano/camel/out?fileName=${date:now:yyyyMMddHHmmssSSS}${exchangeId}${file:size}.xml");
}
});
});
// Inicia o processo de integração
camelContext.start();
Esse pequeno trecho de código faz a leitura de um email pop3 passa por um Processor ( MyMailProcessor )
onde filtra todos os arquivos .xml e direciona para o diretório /home/cristiano/camel/out.
Quando chamamos camelContext.start() ele inicia uma Thread que monitora o email de 3 em 3 segundos ( consumer.delay=3000)
Para parar o processo basta camelContext.stop().
Simples não é? Pois é, também achei que era mentira hhehehe
MyMailProcessor.java:
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import javax.activation.DataHandler;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.commons.lang.StringUtils;
public final class MyMailProcessor implements Processor, Serializable {
/**
*
*/
private static final long serialVersionUID = 3417178693055214881L;
private static final Logger LOGGER = Logger
.getLogger(MyMailProcessor.class.getName());
@Override
public void process(Exchange exchange) throws Exception {
final List<byte[]> result = new ArrayList<byte[]>();
// recupera os anexos
Map<String, DataHandler> attachments = exchange.getIn()
.getAttachments();
if (attachments.size() > 0) {
LOGGER.info("Numero de anexos: " + attachments.size());
for (String name : attachments.keySet()) {
DataHandler dh = attachments.get(name);
final String contentType = dh.getContentType();
final String fileName = dh.getName();
LOGGER.info("Arquivo: " + fileName);
if (isXml(contentType, fileName)) {
// converte o conteudo para array de bytes
byte[] data = exchange.getContext().getTypeConverter()
.convertTo(byte[].class, dh.getInputStream());
result.add(data);
}
}
LOGGER.info("Número de arquivos xmls encontrados: " + result.size());
}
exchange.getOut().setBody(result);
}
private boolean isXml(String contentType, String fileName) {
boolean isValidName = false;
boolean isValidContent = false;
if (!StringUtils.isEmpty(contentType)) {
isValidContent = StringUtils.startsWithAny(contentType.toLowerCase(),
new String[] { "text/xml", "application/xml" });
}
if (!StringUtils.isEmpty(fileName)) {
isValidName = StringUtils.endsWithIgnoreCase(fileName, ".xml");
}
return isValidContent || isValidName;
}
A classe MyMailProcessor implementa a interface org.apache.camel.Processor e faz o filtro dos anexos XMLs e adiciona em uma Lista. Por fim o método split(body()) salva essa lista em forma de arquivos no diretório /home/cristiano/camel/out.
O camel está disponivel para download em http://camel.apache.org
Para que usa maven basta adicionar as dependências no projeto:
<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-mail</artifactId> <version>2.8.2</version> <type>jar</type> </dependency>
Bom é isso espero ter ajudado.. Para quem quiser um livro bom sobre o Apache Camel estou lendo o Camel In Action e é muito bom
.
Abraços
Leitura SmartCard em Java
Galera,
Hoje irei exemplificar como fazer uma leitura de um SmartCard( e-CPF, e-CNPJ ) usando java.
Primeiramente precisamos criar um arquivo para configuração do SmartCard com o seguinte conteudo:
name = SmartCard
library = c:\\windows\\system32\\aetpkss1.dll
Chamarei esse arquivo de token.cfg
Existem duas maneiras de instanciar o Provider: Dinâmicamente e Registrando direto na JDK.
Dinâmicamente:
Security.addProvider(new sun.security.pkcs11.SunPKCS11("c:\\app\\token.cfg"));
Registrando na JDK:
Bastar editar o arquivo $JAVA_HOME/jre/lib/security/java.security e adicionar o provider PKCS11 especificando o arquivo de configuração
# Os 9 demais providers foram ocultados
security.provider.10=sun.security.pkcs11.SunPKCS11 c:\\app\\token.cfg
Para verificar se o SmartCard foi carregado com sucesso basta executar o código abaixo e verificar os aliases.
String senha = "123456"
KeyStore keyStore = KeyStore.getInstance("PKCS11");
keyStore.load(null, senha.toCharArray());
if (keyStore == null) {
throw new Exception("Erro ao carregar o certificado ");
}
Enumeration enumeration = keyStore.aliases();
while (enumeration.hasMoreElements()) {
System.out.println(enumeration.nextElement());
}
Espero ter ajudado.
Adapter com JAXB
Pessoal,
Hoje vou exemplificar como criar um adapter usando JAXB.
Vamos imaginar que você tenha um XML que venha com um valor “x” e você precise converter para uma entidade, enum etc…
No JAXB existe uma maneira muito elegante de fazer isso. Que consiste na criação de um adapter onde ele recebe algum valor de entrada e converte para o valor desejado.
Para fazer isso é muito simples basta extendermos a classe XmlAdapter e implementar seus métodos.
Vejam o código abaixo:
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class MediaTrayAdapter extends XmlAdapter {
@Override
public Integer marshal(MediaTray v) throws Exception {
return v.getValue();
}
@Override
public MediaTray unmarshal(Integer v) throws Exception {
switch (v) {
case 0:
return MediaTray.TOP; // superior
case 1:
return MediaTray.MIDDLE; //mediana
case 2:
return MediaTray.BOTTOM; // inferior
case 3:
return MediaTray.ENVELOPE; // envelope
case 4:
return MediaTray.MANUAL; // manual
case 5:
return MediaTray.LARGE_CAPACITY; // alta capacidade
case 6:
return MediaTray.MAIN; // principal
case 7:
return MediaTray.SIDE; // lateral
default:
return MediaTray.MANUAL;
}
}
}
O método marshal converte e entidade para o valor de origem e o unmarshal retorna a entidade desejada.
Com isso você pode criar suas classes JAXB com Objetos e usar adapters para popular.
Bastando anotar o campo com a seguinte anotação:
@XmlAccessorType(XmlAccessType.FIELD)
public class Impressora {
....
@XmlJavaTypeAdapter(MediaTrayAdapter.class)
private MediaTray bandejaNormal;
...
// gets and setters
}
Com isso você consegue deixar suas classes mais limpas.
Espero ter ajudado.
Qualquer dúvida estarei aqui.
[]s
Injeção de Dependêcia Usando Guice
Galera,
Para quem não sabe o Guice é framework de injeção de dependências criado pelo Google. Ele possui muitos recursos interessantes e vale a pena ser usado. É bem simples e não tem que ficar usando arquivos xmls, pois ele é todo baseado em anotações.
Fiz um exemplo para carregar um EntityManger usando o Guice e vou postar aqui pra vocês.
Primeiramente criamos o que chamamos de Módulo que a parte que faz o criação do objeto.
public class EntityManagerModule extends AbstractModule {
private static ThreadLocal<EntityManager> ENTITY_MANAGER_CACHE = new ThreadLocal<EntityManager>();
@Provides
@Singleton
public EntityManagerFactory provideEntityManagerFactory() {
return Persistence.createEntityManagerFactory("persistence-unit");
}
@Override
protected void configure() {
}
@Provides
public EntityManager provideEntityManager(EntityManagerFactory entityManagerFactory) {
EntityManager entityManager = ENTITY_MANAGER_CACHE.get();
if (entityManager == null) {
ENTITY_MANAGER_CACHE.set(entityManager = entityManagerFactory.createEntityManager());
}
return entityManager;
}
}
O método configure é responsavel pela criação do objeto. Porém ele esta vazio pois quando eu anoto um método com @Provides o Guice entende que esse método cria um objeto.
Também temos a anotação @Singleton que faz com que o objeto só seja criado uma unica vez.
Agora iremos fazer uma classe que irá utilizar um EntityManager.
public final class Teste {
private EntityManager em;
@Inject
public Teste(EntityManager em) {
this.em = em;
}
}
A anotação @Inject é responsável pela injeção da instancia do EntityManager na classe Teste.
Agora vamos instanciar a classe teste:
Injector injector = Guice.createInjector(new EntityManagerModule()); Teste teste = injector.getInstance(Teste.class);
Pronto no código acima criamos uma instancia da classe Teste sem se preocupar com a criação das dependências. O Guice cuida disso pra você
.
Isso foi um exemplo bem simples, Mas o Guice é um framework incrivél que dá pra fazer muita coisa legal.
Sem contar que no site http://code.google.com/p/google-guice tem uma documentação excelente.
Bom é isso..
Até o próximo post.
Extrair dados de um Certificado ICP Brasil
Galera,
Estou fazendo um projeto que envolve certificação digital e precisei fazer uma funcão para extrair dados de um certificado, tais como CPF, CNPJ etc…
Vou postar ela aqui pois pode ser util pra para alguem.
Foi usado a biblioteca BouncyCastle para extrair os dados.
/**
* OID especificados pela ICP Brasil
*/
public static final DERObjectIdentifier OID_PF_DADOS_TITULAR = new DERObjectIdentifier("2.16.76.1.3.1");
public static final DERObjectIdentifier OID_PJ_RESPONSAVEL = new DERObjectIdentifier("2.16.76.1.3.2");
public static final DERObjectIdentifier OID_PJ_CNPJ = new DERObjectIdentifier("2.16.76.1.3.3");
public static final DERObjectIdentifier OID_PJ_DADOS_RESPONSAVEL = new DERObjectIdentifier("2.16.76.1.3.4");
public static final DERObjectIdentifier OID_PF_ELEITORAL = new DERObjectIdentifier("2.16.76.1.3.5");
public static final DERObjectIdentifier OID_PF_INSS = new DERObjectIdentifier("2.16.76.1.3.6");
public static final DERObjectIdentifier OID_PJ_INSS = new DERObjectIdentifier("2.16.76.1.3.7");
public static final DERObjectIdentifier OID_PJ_NOME_EMPRESARIAL = new DERObjectIdentifier("2.16.76.1.3.8");
public static void parse(X509Certificate cert) {
try {
Collection col = X509ExtensionUtil.getSubjectAlternativeNames(cert);
for (Object obj : col) {
if (obj instanceof ArrayList) {
ArrayList lst = (ArrayList) obj;
Object value = lst.get(1);
if (value instanceof DERSequence) {
/**
* DER Sequence
* ObjectIdentifier
* Tagged
* DER Octet String
*/
DERSequence seq = (DERSequence) value;
DERObjectIdentifier oid = (DERObjectIdentifier) seq.getObjectAt(0);
DERTaggedObject tagged = (DERTaggedObject) seq.getObjectAt(1);
String info = null;
DERObject derObj = tagged.getObject();
if (derObj instanceof DEROctetString) {
DEROctetString octet = (DEROctetString) derObj;
info = new String(octet.getOctets());
} else if (derObj instanceof DERPrintableString) {
DERPrintableString octet = (DERPrintableString) derObj;
info = new String(octet.getOctets());
} else if (derObj instanceof DERUTF8String) {
DERUTF8String str = (DERUTF8String) derObj;
info = str.getString();
}
if (info != null && !info.isEmpty()) {
if (oid.equals(SignBean.OID_PF_DADOS_TITULAR) || oid.equals(SignBean.OID_PJ_DADOS_RESPONSAVEL)) {
String nascimento = info.substring(0, 8);
System.out.println("Data Nascimento: " + new SimpleDateFormat("ddMMyyyy").parse(nascimento));
String cpf = info.substring(8, 19);
System.out.println("CPF: " + cpf);
String nis = info.substring(19, 30);
System.out.println("NIS: " + nis);
String rg = info.substring(30, 45);
System.out.println("RG: " + rg);
if (!rg.equals("000000000000000")) {
String ufExp = info.substring(45, 50);
System.out.println("Orgão Expedidor: " + ufExp);
}
} else if (oid.equals(SignBean.OID_PF_INSS)) {
String inss = info.substring(0, 12);
System.out.println("INSS: " + inss);
} else if (oid.equals(SignBean.OID_PF_ELEITORAL)) {
String titulo = info.substring(0, 12);
System.out.println("Titulo de Eleitor: " + titulo);
String zona = info.substring(12, 15);
System.out.println("Zona Eleitoral: " + zona);
String secao = info.substring(15, 19);
System.out.println("Seção: " + secao);
if (!titulo.equals("000000000000")) {
String municipio = info.substring(19, 41);
System.out.println("Municipio: " + municipio);
}
} else if (oid.equals(SignBean.OID_PJ_RESPONSAVEL)) {
System.out.println("Responsavél: " + info);
} else if (oid.equals(SignBean.OID_PJ_CNPJ)) {
System.out.println("CNPJ: " + info);
} else if (oid.equals(SignBean.OID_PJ_INSS)) {
System.out.println("INSS: " + info);
} else if (oid.equals(SignBean.OID_PJ_NOME_EMPRESARIAL)) {
System.out.println("NOME: " + info);
}
}
} else {
System.out.println("Valor desconhecido: " + value);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
Caso tenham alguma dúvida é só enviar como comentário que eu respondo. Pois não tive muito tempo de fazer um passo a passo dessa função.
Espero ter ajudado!
Falows
Sockets em Java
Pessoal,
Boa Tarde!
Hoje acordei pensando o que seria legal postar hoje… Atualmente estou fazendos estudos sobre segurança na web pelo Google University e lendo o segundo slide tem um exemplo de um simples servidor HTTP, ai pensei… porque não falar de Sockets em Java? E esse é o assunto do post de hoje!
Socket é a combinação do endereço IP, um protocolo e sua respectiva porta.
Em java temos a classe java.net.ServerSocket que fica aguardando requisições em uma determinada porta e a classe java.net.Socket que implementa o client.
O Socket é um endpoint usado para estabelecer a conexão entre duas máquinas.
Agora vou mostrar como se implementa um simples HttpServer usando sockets.
Devido ao post ser relacionado a implementção de Sockets em java não vou descrever o protocolo HTTP, caso você não saiba o funcionamento sugiro que cliquem aqui.
Primeiramente tenho uma classe Main para iniciar meu HttpServer.
public class Main {
public static void main(String[] args) {
try {
ServidorHttpSimples sws = new ServidorHttpSimples();
sws.iniciar();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Agora irei explicar o funcionamento.
public class ServidorHttpSimples {
private static final int PORTA = 8080;
private static ServerSocket serverSocket;
public ServidorHttpSimples() throws Exception {
serverSocket = new ServerSocket(PORTA);
}
public void iniciar() throws Exception {
while (true) {
Socket socket = serverSocket.accept();
processRequest(socket);
}
}
}
No código acima repare no construtor:
public ServidorHttpSimples() throws Exception {
serverSocket = new ServerSocket(PORTA);
}
Isso reflete exatamente a definição do socket: tenho um IP que no meu caso é o 127.0.0.1(localhost), um protocolo que eu estou implementando “HTTP” e uma porta “8080″
No metodo iniciar criei um laço infinito e fiz a chamada do metodo serverSocket.accept(), que me retorna um Socket.
Quando chamo esse método faço com que meu Servidor Http esteja pronto para receber requisições na porta 8080.
public void iniciar() throws Exception {
while (true) {
Socket socket = serverSocket.accept();
processaRequisicao(socket);
}
}
Pronto agora já tenho um socket criado, agora preciso tratar minhas requisições que é exatamente o que o método processaRequisicao faz:
private void processaRequisicao(Socket socket) throws Exception {
/** Lendo dados do cliente **/
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//** escrevendo dados cliente **/
OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream());
String request = br.readLine();
String comando = null;
String pathname = null;
try {
/** Parse request **/
StringTokenizer st = new StringTokenizer(request, " ");
comando = st.nextToken();
pathname = st.nextToken();
} catch (Exception e) {
osw.write("HTTP/1.0 400 Bad Request\n\n");
osw.close();
return;
}
if (comando.equals("GET")) {
/**
* Se o comando for GET tenta pegar o arquivo no servidor
*/
buscaArquivo(osw, pathname);
} else {
/**
* Caso contraro retorna status que não foi implementado
*/
osw.write("HTTP/1.0 501 Not Implemented\n\n");
}
/* fecha conexão com o client */
osw.close();
}
Agora que vem a parte interessante, quando recebo uma requisicao consigo ler a requisicao feita ao meu Servidor através do metodo socket.getInputStream() e escrever a partir do metodo socket.getOutputStream()
Para verficar a funcionalidade basta conectar via telnet no meu servidor e fazer uma requisição:
cristiano@phantom:~$ telnet localhost 8080 Trying 127.0.0.1... Connected to localhost.localdomain. Escape character is '^]'. GET /arquivoteste.html HTTP/1.1
Quando executo o comando GET /arquivoteste.html HTTP/1.1 e aperto enter a requisicao e enviada para o servidor e eu uso o BufferedReader#readLine() para pegar esse comando, caso ele exista eu busco o arquivo no servidor usando o metodo buscaArquivo(OutputStreamWriter osw, String pathname) e devolvo o arquivo solicitado escrevendo a saída no meu Socket com o metodo OutputStream#write(String s)
Então para uma chamada GET /arquivoteste.html HTTP/1.1 eu teria o seguinte resultado:
cristiano@phantom:~$ telnet localhost 8080 Trying 127.0.0.1... Connected to localhost.localdomain. Escape character is '^]'. GET /arquivoteste.html HTTP/1.1 HTTP/1.0 404 Not Found Connection closed by foreign host. cristiano@phantom:~$
E a conexao com o servidor é fechada por meio do metodo OutputStream#close() do meu socket.
Método busca arquivo:
private void buscaArquivo(OutputStreamWriter osw, String pathname) throws Exception {
FileReader fr = null;
int c = -1;
StringBuffer sb = new StringBuffer();
/* remove a barra inicial da requisição*/
if (pathname.charAt(0) == '/') {
pathname = pathname.substring(1);
}
/* quando o arquivo não é especificado pega o index.html por padrão */
if (pathname.equals("")) {
pathname = "index.html";
}
/* tenta abrir o arquivo */
try {
fr = new FileReader(pathname);
c = fr.read();
} catch (Exception e) {
/* caso não exista retorna o erro 404 não encontrado */
osw.write("HTTP/1.0 404 Not Found\n\n");
return;
}
/* se o arquivo foi encontrado retorna o codigo 200 OK e o conteudo do arquivo*/
osw.write("HTTP/1.0 200 OK\n\n");
while (c != -1) {
sb.append((char) c);
c = fr.read();
}
osw.write(sb.toString());
}
Bom galera, espero ter ajudado com esse post.
Deixando bem claro que isso está longe de ser um servidor HTTP hehehe fiz isso somente para demonstrar o funcionamento de Sockets em Java.
Falows
Criteria API até que enfim…
Galera,
Para quem sentia saudades da Criteria API do hibernate e não existia no JPA 1.0, agora no Java EE 6, já existe essa fodástica API hehehe.
Vejam como é fácil construir querys dinâmicas usando a Criteria.
EntityManager em = getEm(); CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery query = cb.createQuery(); Root<Entidade> entidade = query.from(Entidade.class); query.select(entidade); List<Entidade> entidades = em.createQuery(query).getResultList();
Isso seria o mesmo que fazer:
SELECT e FROM Entidade e;
Bom agora preciso migrar todas minha querys…
falows