Blogger templates

Comunidade java aberto - Participe da nossa comunidade no facebook (clique aqui)

Visitas

quarta-feira, 28 de novembro de 2012

Criptografia

,


Ao contrário do que muitos pensam, é possível criptografar um texto e descriptografá-lo em seguida e o melhor é que existe uma biblioteca que nos permite fazê-lo de forma rápida, simples e objetiva.
Todos sabem que criar um algoritmo para criptografia não é nada simples e se pensarmos em descriptografar o que criptografamos, este algoritmo ficaria mais complicado ainda, porém encontramos esta biblioteca que nos permite fazê-lo de forma muito simples.
Primeiro baixe a biblioteca Jasypt
Aconselhamos baixar direto no link acima, uma vez que poderá baixar sempre a versão mais recente, porém caso encontre dificuldades, segue o nosso próprio link para baixar a biblioteca jasypt-1.7.1.
A primeira coisa é instanciar a classe BasicTextEncryptor (org.jasypt.util.text.BasicTextEncryptor):
     BasicTextEncryptor bte = new BasicTextEncryptor();
Em posse da instância  de BasicTextEncryptor, basta utilizar seus métodos:
     setPassword(String password)
     decrypt(String encryptedMessage)
     encrypt(String message)
Vamos destacar somente que tanto para o método encrypt, quanto para o método decrypt é necessário setar o password que inclusive é o que garante a segurança de sua criptografia. Como pode ver é muito simples. Segue o código completo:
import org.jasypt.util.text.BasicTextEncryptor;
 
public class Criptografia {
 public static void main(String[] args) {
        String seuTexto = "JavaBr.Com - Teste de criptografia";
        System.out.println("Texto sem criptografia: " + seuTexto);
 
        //instanciamos a classe BasicTextEncryptor
        BasicTextEncryptor bte = new BasicTextEncryptor();
 
        //inserimos uma senha qualquer
        bte.setPassword("A senha que voce quizer");
 
        //criamos uma String que recebe a senha criptografada
        String seuTextoCriptografado = bte.encrypt(seuTexto);
        System.out.println("Seu texto criptografado = " + seuTextoCriptografado);
 
        //criamos uma String que recebe a senha descriptografada
        String seuTextoNovamenteDescriptografado = bte.decrypt(seuTextoCriptografado);
        System.out.println("Texto descriptografado  = " + seuTextoNovamenteDescriptografado);
 
    }
 
}

Produzirá a saída:
Texto sem criptografia: JavaBr.Com - Teste de criptografia
Seu texto criptografado = cl09pC6PcrLUW7AkewZW/YA6H+qCKfxWacYk97SXS++QpCsYdZgC1jzNu4/Cyx1/
Texto descriptografado  = JavaBr.Com - Teste de criptografia
Fonte(javabr)
Continue lendo

Manipulação de Arquivo CSV

,


Pela definição, CSV significa "Comma-separated Value", ou seja, são valores separados por virgula ou por qualquer outro separador. Mas na prática, o formato CSV permite o armazanamento de dados de uma tabela em um arquivo texto, sendo suportado pela maioria das planilhas eletrônicas e SGBD. Em nossa aplicação iremos criar um arquivo CSV com dados de uma tabela e importar dados de um arquivo CSV para a mesma tabela. Em posts posteriores criaremos aplicativos que façam a integração de arquivos CSVs com planilhas excel, xmls e banco de dados.

Sendo a tabela:

NomeTelefoneIdade
Juliana6783-849023
Tatiana6743-748045
Janice6909-938021

Vamos criar um método que gere um arquivo CSV. Segue o código:


//Para a execução das duas classes abaixo é importar algumas classes do
//Java.

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;


public void createCsvFile(){
 
//A estrutura try-catch é usada pois o objeto BufferedWriter exige que as
//excessões sejam tratadas

try{

//Criação de um buffer para a escrita em uma stream
BufferedWriter StrW = new BufferedWriter(new FileWriter("C:\\tabela.csv"));

//Escrita dos dados da tabela
StrW.write("Nome;Telefone;Idade\n"); 

StrW.write("Juliana;6783-8490;23\n");
 
StrW.write("Tatiana;6743-7480;45\n");
 
StrW.write("Janice;6909-9380;21");


//Fechamos o buffer
StrW.close();
 
}catch (FileNotFoundException ex)
{

ex.printStackTrace(); 
}catch (IOException e)
{
e.printStackTrace(); } 
}

Agora vamos criar um método que lê um arquivo CSV e imprima na tela as informações:

public void readCsvFile(){

//A estrutura try-catch é usada pois o objeto BufferedWriter exige que as
//excessões sejam tratadas

try {
//Criação de um buffer para a ler de uma stream
BufferedReader StrR = new BufferedReader(new FileReader("c:\\tabela.csv"));

String Str;

String[] TableLine;

//Essa estrutura do looping while é clássica para ler cada linha
//do arquivo 
while((Str = StrR.readLine())!= null){
//Aqui usamos o método split que divide a linha lida em um array de String//passando como parametro o divisor ";".
TableLine = Str.split(";");

//O foreach é usadao para imprimir cada célula do array de String.
for (String cell : TableLine) {
System.out.print(cell+" "); 

}
System.out.println("\n");
}
//Fechamos o buffer
StrR.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException ex){
ex.printStackTrace();
}

}


Como podemos perceber pelos métodos acima, manipular arquivos CSVs consiste apenas em conhecer algumas caracteristicas das classes String e System.IO do Java. Em posts posteriores veremos como integrar arquivos CSV com xml e banco de dados, assim como outros assuntos relacionados ao JAVA. E você, o que achou desse artigo? Deixe seu comentário, dúvida ou sugestão de novos posts. Até a próxima!!!
Continue lendo

terça-feira, 27 de novembro de 2012

Desenvolvendo Loja Virtual - Parte -01

,

Começamos com uma série de artigos onde vamos desenvolver uma loja virtual completa, utilizando a tecnologia Java EE.

No exemplo, a loja virtual é generica. Você precisa apenas cadastrar os dados conforme sua necessidade.


O que a loja faz?


  • Cadastro de Categorias;
  • Cadastro de Produtos - Com foto (funcionando);
  • Vendas Online; 
  • Controle de Usuários;
  • Controle de Acesso;
  • Produtos em destaque;
  • Listagem de vendas;


Será uma programação incremental, vamos fazendo e testando.
Primeiro ponto, e configurar o ambiente de trabalho.

Baixar IDE Eclipse

Escolha seu sistema operacional. Baixe e Instale.

Para o nosso trabalho, vamos utilizar o Vraptor.
Caso queira saber mais sobre. Acesse:

Documentação Vraptor

Baixe o pacote do nosso projeto e importe para o seu Eclipse.

Projeto

Como importar?

No eclipse,

-> File --- Import
-----> Existing Projects into Workspace
------------> Select archive file: (encontre o projeto)
-------------------------> Clique em Finish

O projeto que importamos está completo.
 Adicione o projeto ao seu Apache Tomcat 7.
E execute.

http://localhost:8080/projeto

Precisamos apenas alterar  a senha do BD e criar um banco para a aplicação.

Baixe o mysql e instale em sua máquina.

Próxima parte -> Configuração do BD, Hibernate

Crud de Categoria.
Crud de Produtos (sem foto ainda).

Veremos  relacionamentos com Hibernate, e taglib.

Wesley Martins.
Desenvolver Web Java.


Dúvidas?
Deixe um comentário.













Continue lendo

sábado, 24 de novembro de 2012

Triggers (Gatilhos)

,



Se até agora você esta acostumado a trabalhar com banco de dados do tipo ISAM ( Dbase , FoxPro, Access , Paradox...); desenvolver uma aplicação para gerenciar os dados neste caso significa criar uma aplicação que faça o controle sobre todo ambiente desde a interface , passando pela manutenção dos dados e as regras de negócios do sistema.

É o sistema que deve controlar e tomar as decisões sobre o que fazer em determinadas situações. Assim em um programa para controlar os produtos de uma empresa quando a quantidade de um produto atingir uma certa quantidade o sistema deverá avisar o operador/usuário para providenciar a reposição do mesmo.

Ao trabalhar com base de dados Cliente/Servidor como SQL Server , Oracle , Informix , dentre outras, podemos usar um recurso muito poderoso chamado Trigger.

Um Trigger é bloco de comandos Transact-SQL que é automaticamente executado quando um comando INSERT , DELETE ou UPDATE for executado em uma tabela do banco de dados.
Os Triggers são usados para realizar tarefas relacionadas com validações , restrições de acesso , rotinas de segurança e consistência de dados ; desta forma estes controles deixam de ser executados pela aplicação e passam a ser executados pelos Triggers em determinadas situações 
  • Mecanismos de validação envolvendo múltiplas tabelas
  • Criação de contéudo de uma coluna derivada de outras colunas da tabela
  • Realizar análise e e atualizações em outras tabelas com base em alterações e/ou incluções da tabela atual
A criação de um Trigger envolve duas etapas :
  1. Um comando SQL que vai disparar o Trigger ( INSERT , DELETE , UPDATE)
  2. A ação que o Trigger vai executar ( Geralmente um bloco de códigos SQL )
Como não poderia deixar de ser , existem certas limatações na utilização de um Trigger :
  • Não é possivel criar um Trigger para uma visão
  • O resultado da execução de um Trigger é retornado para a aplicação que o chamou.
  • O comando WRITETEXT não ativa um Trigger
  • O comando TRUNCATE TABLE não pode ser reconhecido por um Trigger
  • Não podemos usar em um Trigger os seguintes comandos SQL :
    • ALTER DATABASE , ALTER TRIGGER , ALTER PROCEDURE , ALTER TABLE , ALTER VIEW . CREATE DATABASE , CREATE INDEX , CREATE PROCEDURE, CREATE SCHEMA, CREATE TABLE , DROP DATABASE, DROP TABLE , DROP PROCEDURE, DROP TRIGGER, DROP INDEX, GRANT , LOAD DATABASE, REVOKE, RESTORE DATABASE, TRUNCATE TABLE.
Como criar um Trigger
Podemos criar um Trigger usando o comando Create Trigger do SQL Server ou através do Enterprise Manager. A Sintaxe de um Trigger é a seguinte:

CREATE TRIGGER trigger_name 
ON { table | view } 
[ WITH ENCRYPTION ] 
{ 
    { { FOR | AFTER | INSTEAD OF } { [ INSERT ] [ , ] [ UPDATE ] } 
        [ WITH APPEND ] 
        [ NOT FOR REPLICATION ] 
        AS 
        [ { IF UPDATE ( column ) 
            [ { AND | OR } UPDATE ( column ) ] 
                [ ...n ] 
        | IF ( COLUMNS_UPDATED ( ) { bitwise_operator } updated_bitmask ) 
                { comparison_operator } column_bitmask [ ...n ] 
        } ] 
        sql_statement [ ...n ] 
    } 
} 
  1. ON Table - a tabela para o qual o trigger esta sendo criado
  2. FOR - deve ser seguido do tipo de comando que acionam o trigger
  3. AFTER - determina que o trigger somente sera disparado quando todas as rotinas especificadas no comando de disparo forem executadas com sucesso
  4. INSTEAD OF - Determina que o trigger será executado ao invés do comando de disparo do mesmo.
  5. [ DELETE ] [INSERT] [UPDATE] - indicam o tipo de ação que deve disparar o trigger.
Quando você for criar um Trigger deverá definir :
  1. O nome
  2. A Tabela para o qual o Trigger irá ser criado
  3. Quando o Trigger deverá ser disparado
  4. Os comandos que determinam qual ação o Trigger deverá executar
Exemplo de Triggers:

1- O trigger abaixo será disparado quando alguém tentar incluir ou alterar dados na tabela Titles. Ele emite uma mensagem ao usuário. ( 50009 é uma mensagem definida para o usuário em sysmessages.)

USE pubs
IF EXISTS (SELECT name FROM sysobjects
      WHERE name = 'reminder' AND type = 'TR')
   DROP TRIGGER reminder
GO
CREATE TRIGGER reminder
ON titles
FOR INSERT, UPDATE 
AS RAISERROR (50009, 16, 10)
GO

Fonte(macoratti)
Continue lendo

sexta-feira, 23 de novembro de 2012

Executar comando CMD pelo Java

,



  1. public synchronized static String execCommand(final String commandLine) throws IOException {  
  2.   
  3.     boolean success = false;  
  4.     String result;  
  5.   
  6.     Process p;  
  7.     BufferedReader input;  
  8.     StringBuffer cmdOut = new StringBuffer();  
  9.     String lineOut = null;  
  10.     int numberOfOutline = 0;  
  11.   
  12.     try {  
  13.   
  14.         p = Runtime.getRuntime().exec(commandLine);  
  15.   
  16.         input = new BufferedReader(new InputStreamReader(p.getInputStream()));  
  17.   
  18.         while ((lineOut = input.readLine()) != null) {  
  19.             if (numberOfOutline > 0) {  
  20.                 cmdOut.append("\n");  
  21.             }  
  22.             cmdOut.append(lineOut);  
  23.             numberOfOutline++;  
  24.         }  
  25.   
  26.         result = cmdOut.toString();  
  27.   
  28.         success = true;  
  29.   
  30.         input.close();  
  31.           
  32.     } catch (IOException e) {  
  33.         result = String.format("Falha ao executar comando %s. Erro: %s", commandLine, e.toString());  
  34.     }  
  35.   
  36.     // Se não executou com sucesso, lança a falha  
  37.     if (!success) {  
  38.         throw new IOException(result);  
  39.     }  
  40.   
  41.     return result;  
  42.   
  43. }  

Continue lendo

terça-feira, 20 de novembro de 2012

Como usar banco de dados em uma aplicação Android

,


Um dos grandes diferenciais da plataforma android é a grande quantidade de módulos e APIsSQLite que as aplicações tem à  disposição para usar. Eles dão muito poder ao desenvolvedores, permitindo que estes façam coisas que eram impossíveis em outras plataformas móveis.
Um dos mais importantes módulos é o SQLite. Sim, amigos, já temos um SGDB (Sistema gerenciador de bancos de dados) instalado e pronto para usar! E é exatamente o que faremos no artigo de hoje.
Usaremos o content provider para acessar o banco de dados.
Para fazer isso, precisamos implementar os métodos da classe ContentProvider que vimos no artigo passado (query(), delete(), update(), etc…)  para prover ao usuário os métodos para criar, atualizar, deletar e recuperar os dados. Além disso, usaremos a classe SQLiteOpenHelper para gerenciar a conexão com o banco de dados.

A classe SQLiteOpenHelper

A classe SQLiteOpenHelper, como dito anteriormente, será usada para gerenciar o banco de dados. Para usá-la, é preciso criar uma subclasse implementando os métodos abaixo:
  • onCreate() – Este método é chamado quando a conexão com o banco de dados for aberta pela primeira vez. É aqui que criaremos o banco de dados, com o comando sql CREATE.
  • onUpdate() – Este método é chamado quando a versão do banco de dados muda. Por exemplo, digamos que você criou uma nova versão de seu aplicativo que usa uma tabela a mais no banco de dados. Quando esta nova versão for instalada (em um telefone que já possuir a primeira versão) este método será chamado, então você poderá criar apenas a nova  tabela, mantendo os dados do usuário.

O código

O código do QuickNotesProvider fica assim, acessando o banco de dados. A seguir, eu explico algumas coisas que podem gerar dúvidas.
  1. package br.com.felipesilveira.quicknotes;  
  2.   
  3. import java.util.HashMap;  
  4.   
  5. import android.content.ContentProvider;  
  6. import android.content.ContentUris;  
  7. import android.content.Context;  
  8. import android.content.UriMatcher;  
  9. import android.net.Uri;  
  10. import android.provider.BaseColumns;  
  11. import android.content.ContentValues;  
  12. import android.database.Cursor;  
  13. import android.database.sqlite.SQLiteDatabase;  
  14. import android.database.sqlite.SQLiteOpenHelper;  
  15. import android.database.sqlite.SQLiteQueryBuilder;  
  16.   
  17. public class QuickNotesProvider extends ContentProvider {  
  18.   
  19.     // Authority do nosso provider, a ser usado nas Uris.  
  20.     public static final String AUTHORITY =   
  21.         "br.com.felipesilveira.quicknotes.quicknotesprovider";  
  22.       
  23.     // Nome do arquivo que irá conter o banco de dados.  
  24.     private static  final String DATABASE_NAME = "quicknotes.db";  
  25.       
  26.     // Versao do banco de dados.  
  27.     // Este valor é importante pois é usado em futuros updates do DB.  
  28.     private static  final int  DATABASE_VERSION = 1;  
  29.       
  30.     // Nome da tabela que irá conter as anotações.  
  31.     private static final  String NOTES_TABLE = "notes";  
  32.   
  33.     // 'Id' da Uri referente às notas do usuário.  
  34.     private  static final int NOTES = 1;  
  35.   
  36.     // Tag usada para imprimir os logs.  
  37.     public static final String TAG = "QuickNotesProvider";  
  38.       
  39.     // Instância da classe utilitária  
  40.     private DBHelper mHelper;  
  41.       
  42.     // Uri matcher - usado para extrair informações das Uris  
  43.     private static final UriMatcher mMatcher;  
  44.   
  45.     private static HashMap<string, string=""> mProjection;  
  46.       
  47.     static {  
  48.         mProjection = new HashMap<string, string="">();  
  49.         mProjection.put(Notes.NOTE_ID, Notes.NOTE_ID);  
  50.         mProjection.put(Notes.TEXT, Notes.TEXT);      
  51.     }  
  52.       
  53.     static {  
  54.         mMatcher = new UriMatcher(UriMatcher.NO_MATCH);  
  55.         mMatcher.addURI(AUTHORITY, NOTES_TABLE, NOTES);  
  56.     }  
  57.       
  58.       
  59.     /////////////////////////////////////////////////////////////////  
  60.     //           Métodos overrided de ContentProvider              //  
  61.     /////////////////////////////////////////////////////////////////  
  62.     @Override  
  63.     public int delete(Uri uri, String selection, String[] selectionArgs) {  
  64.         SQLiteDatabase db = mHelper.getWritableDatabase();  
  65.         int count;  
  66.         switch (mMatcher.match(uri)) {  
  67.             case NOTES:  
  68.                 count = db.delete(NOTES_TABLE, selection, selectionArgs);  
  69.                 break;  
  70.             default:  
  71.                 throw new IllegalArgumentException(  
  72.                   "URI desconhecida " + uri);  
  73.         }  
  74.        
  75.         getContext().getContentResolver().notifyChange(uri, null);  
  76.         return count;  
  77.     }  
  78.   
  79.     @Override  
  80.     public String getType(Uri uri) {  
  81.             switch (mMatcher.match(uri)) {  
  82.                 case NOTES:  
  83.                     return Notes.CONTENT_TYPE;  
  84.                 default:  
  85.                     throw new IllegalArgumentException(  
  86.                         "URI desconhecida " + uri);  
  87.             }  
  88.     }  
  89.   
  90.     @Override  
  91.     public Uri insert(Uri uri, ContentValues values) {  
  92.         switch (mMatcher.match(uri)) {  
  93.             case NOTES:  
  94.                 SQLiteDatabase db = mHelper.getWritableDatabase();  
  95.                 long rowId = db.insert(NOTES_TABLE, Notes.TEXT, values);  
  96.                 if (rowId > 0) {  
  97.                     Uri noteUri = ContentUris.withAppendedId(  
  98.                                  Notes.CONTENT_URI, rowId);  
  99.                     getContext().getContentResolver().notifyChange(  
  100.                                  noteUri, null);  
  101.                     return noteUri;  
  102.                 }  
  103.             default:  
  104.                 throw new IllegalArgumentException(  
  105.                         "URI desconhecida " + uri);  
  106.         }  
  107.     }  
  108.   
  109.     @Override  
  110.     public boolean onCreate() {  
  111.         mHelper = new DBHelper(getContext());;  
  112.         return true;  
  113.     }  
  114.   
  115.     @Override  
  116.     public Cursor query(Uri uri, String[] projection, String selection,  
  117.             String[] selectionArgs, String sortOrder) {  
  118.             // Aqui usaremos o SQLiteQueryBuilder para construir  
  119.             // a query que será feito ao DB, retornando um cursor  
  120.             // que enviaremos à aplicação.  
  121.             SQLiteQueryBuilder builder = new  SQLiteQueryBuilder();  
  122.             SQLiteDatabase database = mHelper.getReadableDatabase();  
  123.             Cursor cursor;  
  124.             switch (mMatcher.match(uri)) {  
  125.                 case NOTES:  
  126.                     // O Builer receberá dois parametros: a tabela  
  127.                     // onde será feita a busca, e uma projection -   
  128.                     // que nada mais é que uma HashMap com os campos  
  129.                     // que queremos recuperar do banco de dados.  
  130.                     builder.setTables(NOTES_TABLE);  
  131.                     builder.setProjectionMap(mProjection);  
  132.                     break;  
  133.        
  134.                 default:  
  135.                     throw new IllegalArgumentException(  
  136.                           "URI desconhecida " + uri);  
  137.             }  
  138.    
  139.             cursor = builder.query(database, projection, selection,   
  140.              selectionArgs, nullnull, sortOrder);  
  141.   
  142.             cursor.setNotificationUri(getContext().getContentResolver(), uri);  
  143.             return cursor;  
  144.     }  
  145.   
  146.     @Override  
  147.     public int update(Uri uri, ContentValues values, String selection,  
  148.             String[] selectionArgs) {  
  149.             SQLiteDatabase db = mHelper.getWritableDatabase();  
  150.             int count;  
  151.             switch (mMatcher.match(uri)) {  
  152.                 case NOTES:  
  153.                     count = db.update(NOTES_TABLE, values,   
  154.                                                      selection, selectionArgs);  
  155.                     break;     
  156.                 default:  
  157.                     throw new IllegalArgumentException(  
  158.                             "URI desconhecida " + uri);  
  159.             }  
  160.        
  161.             getContext().getContentResolver().notifyChange(uri, null);  
  162.             return count;  
  163.     }  
  164.       
  165.     /////////////////////////////////////////////////////////////////  
  166.     //                Inner Classes utilitárias                    //  
  167.     /////////////////////////////////////////////////////////////////  
  168.     public static final class  Notes implements  BaseColumns {  
  169.         public static final Uri CONTENT_URI = Uri.parse("content://"  
  170.                     + QuickNotesProvider.AUTHORITY + "/notes");  
  171.        
  172.         public static final String CONTENT_TYPE =   
  173.                 "vnd.android.cursor.dir/" + QuickNotesProvider.AUTHORITY;  
  174.        
  175.         public static final String NOTE_ID = "_id";  
  176.        
  177.         public static final String TEXT = "text";  
  178.     }  
  179.       
  180.     private static class DBHelper extends SQLiteOpenHelper {  
  181.        
  182.         DBHelper(Context context) {  
  183.             super(context, DATABASE_NAME, null, DATABASE_VERSION);  
  184.         }  
  185.        
  186.         /* O método onCreate é chamado quando o provider é executado pela 
  187.          * primeira vez, e usado para criar as tabelas no database 
  188.          */  
  189.         @Override  
  190.         public void onCreate(SQLiteDatabase db) {  
  191.             db.execSQL("CREATE TABLE " + NOTES_TABLE + " (" +   
  192.                     Notes.NOTE_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +   
  193.                     Notes.TEXT + " LONGTEXT" + ");");  
  194.         }  
  195.               
  196.         /* O método onUpdate é invocado quando a versão do banco de dados 
  197.          * muda. Assim, é usado para fazer adequações para a aplicação 
  198.          * funcionar corretamente. 
  199.          */    
  200.         @Override  
  201.         public void onUpgrade(SQLiteDatabase db,   
  202.                                       int oldVersion, int newVersion) {  
  203.             // Como ainda estamos na primeira versão do DB,  
  204.             // não precisamos nos preocupar com o update agora.  
  205.         }  
  206.     }  
  207. }  
  208.   
  209. </string,></string,>  

Cursores

O primeiro conceito importante a se falar é o conceito dos Cursores. Como você deve percebido, este é o tipo de retorno do método query(), e não é por acaso: Os cursores são “apontadores de dados” do banco de dados – ou seja, uma interface que permite o acesso aos dados retornados pela query enviada pelo usuário.

notifyChanges()

Em todos os métodos em que alteramos o banco de dados (inserimos, deletamos ou modificamos dados) é importante chamar o método modifyChanges(). Isso fará com que as aplicações que estejam utilizando este conjunto de dados sejam notificadas, permitindo a estas atualizar também os dados mostrados ao usuário.

Fonte(felipsilveira)
Continue lendo
 

Java Aberto Copyright © 2011 -- Template created by O Pregador -- Powered by Blogger