quinta-feira, 17 de julho de 2008

Usando o Spring para trabalhar com LDAP

Olá amiguinhos,

Estou construindo uma aplicação com GWT e Spring, para me ajudar na hora de administrar usuários do Squid, pelo LDAP. O LDAP é muito bom para centralizar contas de usuários e em breve minha aplicação funcionará também para PDC no Samba, contas de e-mails e tudo que usa o LDAP. Eu vou disponibilizar para a comunidade assim que terminado.

Bom, vamos lá. Não vou entrar em muitos detalhes para a configuração do LDAP, mas deixe a base principal como dc=teste,dc=com,dc=br e o usuário administrador como cn=admin,dc=teste,dc=com,dc=br e a senha como teste.

Crie um projeto no Eclipse, se você está usando Maven, melhor ainda, adicione as dependências do spring-ldap lá, senão, acesse o site www.springframework.org/ldap e faça o download da biblioteca e suas dependências, e adicione no projeto.

Crie um arquivo applicationContext.xml e adicione o seguinte:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

<bean id="contextSource"
class="org.springframework.ldap.core.support.LdapContextSource">
<property name="url" value="ldap://localhost:389" />
<property name="base" value="dc=teste,dc=com,dc=br" />
<property name="userDn" value="cn=admin,dc=teste,dc=com,dc=br" />
<property name="password" value="teste" />
</bean>

<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
<constructor-arg ref="contextSource" />
</bean>

<bean id="userDao" class="br.org.teste.server.UserLdapDao">
<property name="ldapTemplate" ref="ldapTemplate" />
</bean>

</beans>


Beleza, a parte do Spring já está configurada, agora só fazermos um DAO e um POJO para trabalharmos.

Bom, se você for trabalhar com o objeto do LDAP inetOrgPerson, você pode fazer a seguinte estrutura na classe POJO:

public class UserLdap {

private String fullName;
private String lastName;
private String uid;
private String givenName;
private String userPassword;
private String description;
private String mail;

public String getFullName() {
return fullName;
}

public void setFullName(String fullName) {
this.fullName = fullName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getUserId() {
return uid;
}

public void setUserId(String userId) {
this.uid = userId;
}

public void setGivenName(String givenName) {
this.givenName = givenName;
}

public String getGivenName() {
return givenName;
}

public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}

public Object getUserPassword() {
return userPassword;
}

public void setDescription(String description) {
this.description = description;
}

public String getDescription() {
return description;
}

public void setMail(String mail) {
this.mail = mail;
}

public String getMail() {
return mail;
}
}


Agora vamos fazer a classe DAO. Vou mostrar a classe que eu fiz para as minhas necessidades, se você quiser se aprofundar mais, acesse o site http://static.springframework.org/spring-ldap/docs/1.2.1/reference/

O difícil é entender o Spring, depois que você entende como funciona, a documentação no site se torna muito mais fácil.

Então vamos lá, crie a classe DAO com o seguinte conteúdo:

public class UserLdapDao {


private LdapTemplate ldapTemplate;


/**
* Define um LdapTemplate do Spring
* @param ldapTemplate Define um objeto LdapTemplate
* @author anderson
* @version 1.0
*/
public void setLdapTemplate(LdapTemplate ldapTemplate) {
this.ldapTemplate = ldapTemplate;
}


/**
* Metodo que compila um DN
* @param user Define um objeto UserLdap
* @return Retorna um objeto Name
*/
public Name buildDn(UserLdap user) {
DistinguishedName dn = new DistinguishedName();
dn.add("cn", user.getFullName());

return dn;
}


/**
* Metodo que insere uma nova entrada no Ldap
* @param user Define um objeto UserLdap
* @author anderson
* @version 1.0
*/
public void create(UserLdap user) {
Name dn = buildDn(user);
ldapTemplate.bind(dn, null, buildAttributes(user));
}


/**
* Metodo que remove uma entrada no Ldap
* @param user Define um objeto UserLdap
* @author anderson
* @version 1.0
*/
public void delete(UserLdap user) {
Name dn = buildDn(user);
ldapTemplate.unbind(dn);
}


/**
* Metodo que atualiza um registro no Ldap
* @param user Define um objeto UserLdap
* @author anderson
* @version 1.0
*/
public void update(UserLdap user) {
Name dn = buildDn(user);
ldapTemplate.rebind(dn, null, buildAttributes(user));
}


/**
* Metodo que compila os atributos para ser inserido, removido ou atualizado
* @param user Define um objeto UserLdap
* @return Retorna um objeto Attributes
* @author anderson
* @version 1.0
*/
private Attributes buildAttributes(UserLdap user) {
Attributes attrs = new BasicAttributes();
BasicAttribute ocattr = new BasicAttribute("objectclass");

ocattr.add("top");
ocattr.add("inetOrgPerson");

attrs.put(ocattr);
attrs.put("sn", user.getLastName());
attrs.put("givenName", user.getGivenName());
attrs.put("uid", user.getUserId());
attrs.put("userPassword", user.getUserPassword());
attrs.put("description", user.getDescription());
attrs.put("mail", user.getMail());

return attrs;
}


/**
* Pega todo os registros do Ldap da classe inetOrgPerson
* @return Retorna uma lista de resultados
* @author anderson
* @version 1.0
*/
@SuppressWarnings("unchecked")
public List getAll() {
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectclass","inetOrgPerson"));
filter.and(new EqualsFilter("objectclass","person"));

return ldapTemplate.search("",
filter.encode(), new PersonAttributesMapper());
}


/**
* Pesquisa injetando os resultados no objeto UserLdao
* @param uid Define um uid para a consulta (Ex.: uid=teste)
* @return Retorna um objeto UserLdap
* @author anderson
* @version 1.0
*/
@SuppressWarnings("unchecked")
public List find(String uid) {
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectclass","inetOrgPerson"));
filter.and(new WhitespaceWildcardsFilter("uid",uid));

return ldapTemplate.search("",
filter.encode(), new PersonAttributesMapper());
}


/**
* Classe interna para atribuir os valores para um pojo UserLdap
* @author anderson
* @version 1.0
*/
private class PersonAttributesMapper implements AttributesMapper {

public Object mapFromAttributes(Attributes attributes)
throws NamingException {

byte[] senha = (byte[])attributes.get("userPassword").get();

UserLdap user = new UserLdap();
user.setFullName((String)attributes.get("cn").get());
user.setLastName((String)attributes.get("sn").get());
user.setUserId((String)attributes.get("uid").get());
user.setGivenName((String)attributes.get("givenName").get());
user.setMail((String)attributes.get("mail").get());
user.setUserPassword(new String(senha));
user.setDescription((String)attributes.get("description").get());

return user;
}

}
}


O método buildAttributes e a classe interna PersonAttributesMapper são os mais importantes e que fazem o negócio funcionar. O método buildAttributes compila os atributos do objeto inetOrgPerson para a base LDAP, você pode definir o objectclass e seus atributos, quais você quiser. A classe interna PersonAttributesMapper retorna no seu POJO, os valores da pesquisa que você solicitou.

E para chamar o DAO, é simples. Na classe que você precisar, basta fazer o seguinte:

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
new String[] { "applicationContext.xml" });
UserLdapDao userDao = (UserLdapDao) ctx.getBean("userDao");
List resultado = userDao.find("uid=teste");


O Spring é mil e uma utilidades, dá para trabalhar só com ele tranquilamente em seu projeto. Estou gostando de usar ele e a cada dia aprendo alguma coisa nova.

Enjoy...

sábado, 12 de julho de 2008

Problema ao usar o DialogBox no GWT 1.5-RC1

Olá amiguinhos,

Eu migrei a versão do GWT no meu sistema para 1.5-RC1, porque estava impossível trabalhar com o Hibernate corretamente, sem gambiarras, sem os recursos do Java 5, como Generics, Annotations, etc.

Na migração, percebi que as funções das janelas feitas pelo DialogBox não mais funcionava. Fiquei louco e fiz vários testes e descobri o problema. Agora eu não sei se isso é um bug ou de agora em diante vai ser assim. Eu criava o dialog box assim:

public class Teste extends DialogBox {

public Teste() {
setText("Teste");
setSize("200","200");
center();

final Button btFechar = new Button("Fechar", new ClickListener() {
public void onClick(Widget sender) {
hide();
}

});
}
}


Depois ao instanciar a classe, basta chamar o método show(). Isso funciona no GWT 1.4, inclusive no Swing e AWT também. Agora para funcionar tem que ser feito assim:

public class Teste {

public Teste() {
DialogBox d = createDialog();
d.setSize("200","200");
d.center();
d.show();
}


public DialogBox createDialog() {
final DialogBox dialogBox = new DialogBox();
dialogBox.ensureDebugId("cwDialogBox");
dialogBox.setText("Teste");

Button btFechar = new Button("Fechar", new ClickListener() {
public void onClick(Widget sender) {
hide();
}

});

dialogBox.setWidget(btFechar);

return dialogBox;
}
}


Vamos torcer para ser apenas um bug da versão release candidate.

Enjoy...

quinta-feira, 10 de julho de 2008

VistaFei - Ferramenta RAD para GWT

Olá amiguinhos,

Hoje estava dando umas voltas pelo Orkut e achei uma comunidade relacionada ao GWT. E um cara falou do tal VistaFei. Entrei no site e já vi de cara que era free e tinha uma versão enterprise. Fiz o download dele e logo me surpriendi com a facilidade do programa. Eles usaram uma versão do Eclipse e trabalharam o plugin deles em cima do Eclipse, então se você só quer uma ferramenta para desenhar telas, está mais que bom.

http://www.wirelexsoft.com/VistaFei.html

Enjoy...

terça-feira, 8 de julho de 2008

Usando o Spring para enviar e-mails

Olá amiguinhos,

Em uma de minhas pesquisas, percebi que não tem um material bem explicativo sobre o Spring quando se trata de usar outras bibliotecas ou frameworks para executar tal serviço. Um amigo me explicou a filosofia do Spring, que por sinal é bem simples. A partir daí, eu entendi como funciona e agora da pra por pra funcionar qualquer coisa.

O Spring é interessante quando você quer criar uma instancia única para a aplicação inteira. O Hibernate por exemplo, o objeto SessionFactory é gigantesco e ficar instanciando isso o tempo todo, ou mais de uma vez, vai causar uma lentidão no sistema. Eu migrei o meu sistema Open Source, usando Spring junto com o Hibernate, o tempo de resposta de uma transação, mudou surpreendentemente. Também estou usando o Spring com o JavaMail. Não notei muita diferença de velocidade, mas pode ser muito útil mais pra frente quando o sistema ter que enviar e-mails em massa automaticamente para os administradores. Quem quiser conferir meu sistema Open Source, acesse http://articulus.sourceforge.net

Bom, vamos ao que interessa. Já expliquei a filosofia do Spring, ele cria uma instancia única para trabalhar no sistema inteiro. Mas é claro que ele não faz só isso, mas é sua principal caracteristica. Crie um projeto qualquer e adicione as bibliotecas do Spring e do JavaMail. Primeiro de tudo, edite seu web.xml da seguinte forma:

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:WEB-INF/classes/*.*</param-value>
</context-param>

<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>


Fazendo isso, o Spring vai procurar no contexto dele, os beans que serão instanciados. Próximo passo é criar um arquivo chamado applicationContext.xml. Se você criou um projeto pelo Maven, salve no diretório resources, senão salve em WEB-INF, junto com o web.xml.

Vamos criar os beans que serão instanciados da seguinte forma:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

<bean id="mailSender" autowire="byName"
class="org.springframework.mail.javamail.JavaMailSenderImpl">

<property name="host" value="mail.seuhost.com.br" />

</bean>


<bean id="mailMessage" autowire="byName"
class="org.springframework.mail.SimpleMailMessage">

<property name="from"
value="teste@teste.com.br" />
<property name="to"
value="outroteste@teste.com.br" />
<property name="subject"
value="Teste" />
<property name="text"
value="Teste do Spring com o JavaMail" />

</bean>


<bean id="sendMail" autowire="byName"
class="br.org.teste.SendMail">

<property name="mailSender" ref="mailSender" />

</bean>

</beans>


Agora o mais importante, você vai ter que criar as classes e seus atributos, exatamente como criou nos beans, assim o Spring vai fazer a injeção nos objetos conforme você declarou.

Crie uma classe chamada SendMail e um pacote chamado br.org.teste e salve a classe lá dentro. Crie a seguinte estrutura:

public class SendMail {

private JavaMailSender mailSender;
private SimpleMailMessage mailMessage;

public void setMailSender(JavaMailSender mailSender) {
this.mailSender = mailSender;
}

public void setMailMessage(SimpleMailMessage mailMessage) {
this.mailMessage = mailMessage;
}

public void send() {
mailSender.send(mailMessage);
}
}


Reparam nas propriedades da classe? Possui os mesmos nomes dos beans, assim quando você for chamar o bean, ele vai fazer a injeção dos objetos pelo nome.

Agora crie uma classe que vai chamar o SendMail, pode ser um Servlet mesmo. Para chamar faça o seguinte:

ClassPathXmlApplicationContext ctx = 
new ClassPathXmlApplicationContext(
new String[] {"applicationContext.xml"});

SendMail send = (SendMail)ctx.getBean("sendMail");
send.send();


Simples né? Muita gente se embaralha totalmente no Spring, mas ele é mais simples do que parece. Eu também penei muito pra entender. Dizem por ae que não precisa invocar o contexto usando a classe ClassPathXmlApplicationContext, que o Spring faz a injeção automaticamente, mas nos meus testes ele só dava NullPointer dae eu desisti. Vou pesquisar mais. Amanhã ou depois eu posto como se faz para trabalhar com o Hibernate e Spring.

Enjoy...

quarta-feira, 2 de julho de 2008

Internacionalização com o GWT

Olá amiguinhos.

Poucos sabem mas estou desenvolvendo um projeto Open Source, junto com a minha amiga Laydy. E estou utilizando o GWT e ao longo do projeto, descubro muitas coisas e vou postando aqui. O projeto está no começo e pensei na internacionalização. Se eu fosse fazer isso no fim do projeto, seria quase o mesmo que redesenvolver tudo, então resolvi acelerar isso agora. Pesquisei e fui direto ao site do GWT e lá explica detalhadamente (A documentação do GWT é a melhor que eu já vi). Então vou resumir aqui o básico, se precisarem de mais recursos, acessem o esse link .

Primeiro, adicione o seguinte no seu arquivo *.gwt.xml:

<inherits name="com.google.gwt.i18n.I18N"/>


Depois, crie uma interface em algum pacote de sua escolha, vamos nomea-la de Teste:

public interface Teste extends Constants {
String helloWorld();
String goodByeWorld();
}


Depois crie um arquivo com o mesmo nome da interface, chamado Teste.properties, com a seguinte estrutura:

helloWorld = Olá mundo!
goodByeWorld = Tchau mundo!


Simples assim. O nome da interface é a mesma do arquivo properties, assim o GWT sabe qual arquivo pegar. E os métodos da interface, são os mesmos nomes das propriedades. Agora na sua classe principal, faça o seguinte:

Teste teste = (Teste)GWT.create(Teste.class);
Window.alert(teste.helloWorld());
Window.alert(teste.goodByeWorld());


Simples não? O problema é se o sistema for gigante, vai dar trabalho ficar criando isso hehehe. Mas vai da sua criatividade, você pode criar uma classe para tratar isso e um ComboBox para o usuário escolher.

Enjoy...

terça-feira, 1 de julho de 2008

Recarregando a página com GWT

Olá amiguinhos.

Primeiro dia do mês e primeiro post do mês. Descobri uma forma de executar métodos nativos pelo GWT. E para recarregar a sua página, não é diferente. Precisa executar um método (função) do JavaScript para dar um reload na página. Eu não testei com outras coisas do tipo, alterar barra de status, título, usar o document.write, entre outros. Até porque o GWT já fornece isso para você. Se alguém encontrar um meio de recarregar a página que seja nativo do GWT, por favor me avise.

Em alguma classe qualquer, crie o seguinte método:

private native void reload() /*-{
$wnd.location.reload();
}-*/;


O encapsulamento fica a seu critério, o importante é a palavra-chave native. Eu não pesquisei muito sobre o significado do $wnd mas funcionando já está perfeito hehe.

Enjoy...

domingo, 22 de junho de 2008

Eliminando o XML de configuração do Hibernate

Olá amiguinhos,

Você ainda usa o arquivo hibernate.cfg.xml? Pois é, eu também usava, até uns dias atrás. Vou explicar como é fácil usar a classe Configuration do Hibernate.

Suponho que você esteja usando um construtor para iniciar as configurações do Hibernate. Veja só como ficaria o construtor.

 public HibernateInitialize() {
Configuration cfg = new AnnotationConfiguration()
.addAnnotatedClass(SuaClasseAnotada.class)
.setProperty(Environment.HBM2DDL_AUTO, "update")
.setProperty(Environment.SHOW_SQL, "false")
.setProperty(Environment.DIALECT,
"org.hibernate.dialect.MySQLInnoDBDialect")
.setProperty("hibernate.connection.driver_class",
"com.mysql.jdbc.Driver")
.setProperty("hibernate.connection.url",
"jdbc:mysql://localhost:3306/test")
.setProperty("hibernate.connection.username", "test")
.setProperty("hibernate.connection.password", "test")
.setProperty("hibernate.connection.pool_size", "10");

SessionFactory sf = cfg.buildSessionFactory();
session = sf.openSession();
tx = session.beginTransaction();
}


Dispensa comentários né? Você acaba de montar a mesma estrutura do XML mas dentro da classe que faz a inicialização do Hibernate.

Nesse link você encontra todas as propriedades para JDBC do Hibernate.

Enjoy...

sexta-feira, 20 de junho de 2008

Configurando cluster com JBoss

Olá amiguinhos,

Tive que fazer uma tarefa aqui no trabalho e não encontrava a solução. Precisava fazer um cluster com o Tomcat, sendo que, se eu desse deploy em um servidor Tomcat, o outro também deveria receber esse deploy. E não estava acontecendo isso e eu estava ficando desesperado já. Resolvi perguntar para meu professor de Protocolos, Cléber, se ele já havia feito cluster com o Tomcat. Ele me deu a dica de usar o JBoss.

O JBoss é um servidor de aplicações J2EE, assim como o Tomcat, mas com recursos bem melhores. Se quiser saber mais sobre o JBoss, clique aqui.

O JBoss já vem pronto para ser cluster. Você não precisa fazer nenhuma configuração se você não quiser, se for algo bem simples é claro. Vou ensinar como fazer um cluster conforme o meu cenário.

Supondo que você instalou o JBoss em /opt/jboss-4.2.2.GA. Eu criei um link simbólico chamado jboss para facilitar. Acesse o diretório /opt/jboss/bin e execute o seguinte comando:

# ./run.sh -c all -b 172.16.5.30


Onde -c é para informar qual configuração você quer, que é all, e -b é o seu IP. Agora acesse o diretório /opt/jboss/server e execute um ls para você ver. Ali fica os diretórios all, default e minimal. Como indicamos que seria o all, vamos trabalhar dentro do diretório all. É um pouco diferente o esquema do JBoss mas logo você acostuma.

Por padrão, o JBoss trabalha a comunicação entre os clusters, usando o protocolo UDP. Fica a seu critério. Se sua rede for um pouco instável, é recomendado você usar o protocolo TCP, pois é orientado a conexão.

Se você quiser usar o TCP, você precisa ter que fazer um trabalho muito árduo. Foi uma das configurações mais complicadas que eu já fiz e sinceramente, espero não precisar fazer mais. Hehehehehe.

Abra o seguinte arquivo:

# vim /opt/jboss/server/all/deploy/cluster-service.xml


Procure a tag <Config> e comente ela da seguinte forma:

<!--<Config>
....
....
</Config>-->


Um pouco mais para baixo, tem outra tag <Config> mas ela já está comentada. É a configuração para TCP. Descomente-a. E dentro da tag <Config> procure a tag <TCPPING> e altere o atributo initial_hosts da seguinte forma:

<TCPPING 
initial_hosts="${jboss.bind.address}[7800],172.16.5.163[7800]"
port_range="3"
timeout="3000"
down_thread="false" up_thread="false"
num_initial_members="3"/>


Onde ${jboss.bind.address}[7800] pega seu IP local e o outro IP seria o outro nó do seu cluster. Você pode indicar quantos você quiser. O TCPPING amarra os principais nós ao seu cluster. Assim ele não fica procurando e já vai direto ao nó.

Dificil, não? É eu sei, dá vontade de formatar o PC e começar tudo de novo de tão complicado hehehehehe.

Farm War Deployment


Bom, se você já deu uma brincada no JBoss para ver como ele funciona, já percebeu que para fazer deploy nele, basta apenas copiar o .war para o diretório /opt/jboss/server/all/deploy. Mas no nosso caso, precisamos replicar a aplicação para todos os nós, assim, você faz 1 deploy e ele se encarrega de mandar para os outros nós automaticamente. Meus olhos enxeram de lágrimas quando eu vi a facilidade de fazer isso. Basta copiar o .war para o diretório /opt/jboss/server/all/farm.

Fique olhando no console, onde você executou o comando run.sh, o que ele fez.

Simples, não? Ah, um detalhe muito importante. Se você configurou 1 nó como TCP, todos os outros precisam ser TCP também. Configure os outros nós conforme a configuração acima e execute o comando run.sh da mesma forma, apenas alterando o IP.

Espero ter ajudado alguém com esse post.

Enjoy...

terça-feira, 17 de junho de 2008

Trabalhando com Threads e evitando congelamento

Olá amiguinhos,

Vou ensinar um esquema que me ajudou por bastante tempo. Controle por iterações no sistema. Um objeto do tipo observador, irá acompanhar as mudanças do sistema.

Vamos lá, crie a seguinte classe, que será nossa interface gráfica principal:

package br.org.testethread;

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Principal extends JFrame {

private static final long serialVersionUID = 1L;

public Principal() {
super("Teste Thread");
setSize(150, 150);

Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
int w = getSize().width;
int h = getSize().height;
int x = (dim.width-w) / 2;
int y = (dim.height-h) / 2;
setLocation(x, y);


JPanel p = new JPanel();

final JLabel lb = new JLabel("0");
final JButton bt = new JButton("Clique aqui!");

bt.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {
for (int i=0; i < 5000000; i++) {
lb.setText(String.valueOf(i));
}
}

});

p.add(lb);
p.add(bt);

getContentPane().add(p);
}


public static void main(String[] args) {
new Principal().setVisible(true);
}

}




Rode o programa e clique no botão para você ver o que acontece. A interface vai congelar, dependendo do seu processador é claro. Se sua máquina for muito potente, aumente a quantidade de laços. Aqui no meu, tive que deixar em 5 milhões para ficar congelada a tela.

Para resolver esse problema, crie uma classe chamada Observador com a seguinte estrutura:

package br.org.testethread;

import java.util.Observable;
import java.util.Observer;

public class Observador extends Observable implements Runnable {

public Observador(Observer observador) {
// Adiciona o objeto observador a lista de observadores
addObserver(observador);
}

public void run() {
int i;
for (i = 0; i <= 10; i++) {
// Notifica o processamento a cada 10 iterações
if ((i % 10 == 0)) {
notifyObservers(new Integer(i));
setChanged();
}
}

// Notifica fim do processo
notifyObservers(new Boolean(true));
setChanged();
}
}


Já temos a nossa classe do tipo Observer, ela vai observar as alterações dos objetos a cada 10 iterações e vai notificar os observadores. Agora precisamos fazer algumas alterações na nossa classe Principal, ela deverá ficar da seguinte forma:

package br.org.testethread;

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

// Adiciona a interface Observer
public class Principal extends JFrame implements Observer {

private static final long serialVersionUID = 1L;

// Cria um objeto do tipo Thread
private Thread processo;

// Declara o label para uso global
private JLabel lb;

public Principal() {
super("Teste Thread");
setSize(150, 150);

Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
int w = getSize().width;
int h = getSize().height;
int x = (dim.width - w) / 2;
int y = (dim.height - h) / 2;
setLocation(x, y);

JPanel p = new JPanel();

lb = new JLabel("0");
final JButton bt = new JButton("Clique aqui!");

bt.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {
// metodo que vai criar uma nova thread
executaProcesso();
}

});

p.add(lb);
p.add(bt);

getContentPane().add(p);
}

public static void main(String[] args) {
new Principal().setVisible(true);
}


private void executaProcesso() {
if (processo == null) {
processo = new Thread(new Observador(this));
processo.start();
} else {
JOptionPane.showMessageDialog(this,
"O processo ainda está em execução!");
}
}

public void update(Observable o, Object arg) {
if (arg instanceof Integer) {
// O laco foi transportado para essa parte
for (int i = 0; i < 5000000; i++) {
lb.setText(String.valueOf(i));
}
} else if (arg instanceof Boolean) {
if (((Boolean) arg).booleanValue()) {
JOptionPane.showMessageDialog(this,
"Processo terminado!");
}
}
}
}


Agora clique no botão para você ver. Você vai acompanhar a incrementação sem que a tela congele. Enquanto ele continua incrementando, experimente clicar no botão novamente para ver o que acontece. Ele te alerta que o processo ainda não terminou. A interface Observer vai "observar" o processo de acordo com a classe Observador. Não é muito difícil de entender, mas você precisa ter uma noção básica de Thread para entender.

Não testei esse esquema para Web, quem quiser testar e comentar aqui, seria legal. Mas acredito que para Web o esquema é meio diferente.

Enjoy...

segunda-feira, 16 de junho de 2008

Fazendo uma conexão bridge no VirtualBox

Olá amiguinhos,

Muita gente gosta de usar o VirtualBox por ser leve e prático e ser opensource. Mas um problema é que ele não faz conexão por bridge, sendo assim, impossível o seu sistema operacional se comunicar com o sistema operacional virtualizado. Mas, sempre existe um esqueminha né? Fiz esses testes no Ubuntu e no Debian e funcionou perfeitamente. Vamos lá.

Instale os seguintes pacotes:

# aptitude install bridge-utils uml-utilities


Agora vamos criar as interfaces que farão a conexão bridge. Vamos utilizar a interface eth0 para fazer o bridge. Se você possui uma conexão pppoe utilize ela, ou qualquer outra interface que esteja recebendo a conexão. Execute o seguinte comando:

# tunctl -t tap1 -u anderson


Com esse comando, criamos a interface tap1 para ser usada pelo usuário anderson. Essa interface que será usada no VirtualBox. Agora vamos criar uma interface de bridge com o seguinte comando:

# brctl addbr br0


Vamos colocar a eth0 (ou sua interface de conexão escolhida) em modo promiscuo, para aceitar conexãoes de outros MACs. Execute o seguinte comando:

# ifconfig eth0 0.0.0.0 promisc


Agora vamos adicionar a interface eth0 a interface de bridge. Execute:

# brctl addif br0 eth0


Preciamos definir um IP para nossa interface de bridge. Seja por DHCP ou estático:

# dhclient3 br0


ou

# ifconfig br0 192.168.0.10


Adicionamos a interface virtual a interface bridge:

# brctl addif br0 tap1


Terminamos a configuração da nossa conexão bridge, vamos levantar a interface tap1:

# ifconfig tap1 up


Agora vamos configurar o VirtualBox para receber essa conexão. Abra seu VirtualBox. Nas preferências de sua máquina virtual, clique em Rede:



Na opção Ligado a, escolha Interface do Hospedeiro. Vai abrir uma caixa de texto abaixo denominado Nome da Placa de Rede, digite tap1:



Clique em OK. Agora antes de inicializar a máquina virtual, é preciso dar permissão de escrita em dois arquivos:

# chmod 666 /dev/net/tun
# chown root:vboxusers /dev/net/tun


Agora inicie a sua máquina virtual. Se estiver com o DHCP configurado, provavelmente ele vai pegar o IP da rede e as máquinas conseguirão pingar na sua máquina virtual.

Espero ter ajudado.

Enjoy...

quinta-feira, 12 de junho de 2008

Salvando fotos no banco de dados com Hibernate

Olá amiguinhos,

Vi nos fóruns por ae que muita gente tem dúvida quanto a isso. Eu particularmente, prefiro salvar no banco de dados, se forem fotos simples de um cadastro. Acho que evita muitos problemas futuramente.

O arquivo com todos os arquivos do projeto pode ser baixado nesse link: Download

Nesse exemplo que vou ensinar é bem simples, nem me dei ao luxo de fazer uma mega interface com o Swing, usei o FlowLayout como padrão mesmo e taquei os componentes lá. A beleza do negócio está no Hibernate hehe. Bom, vamos lá, vou ensinar passo a passo. Estou usando o Maven como gerenciador de projetos, que na minha opinião, é perfeito. Mas se você não quiser usar o Maven, basta adicionar no Classpath as bibliotecas do Hibernate e MySQL. Antes de começar, verifique se você possui o MySQL instalado na sua máquina, e então crie um database com o nome de hibernate_object:

CREATE DATABASE 'hibernate_object';


Crie um usuário para esse database agora com o seguinte comando:

GRANT ALL ON hibernate_object.* TO 
'hibernate'@localhost IDENTIFIED BY 'hibernate123';


Perfeito!!! Agora pode fechar o MySQL que agora vamos só trabalhar com Java. Se você não for usar o Maven, crie um projeto com o nome de HibernateObject. Se estiver usando Maven, crie um archtype padrão e adicione as dependências do Hibernate e MySQL:

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>br.org.hibernateobject</groupId>
<artifactId>HibernateObject</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>HibernateObject</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.3.1.GA</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
</dependencies>
</project>


Para criar a estrutura de diretórios padrão do Maven, basta usar esse comando (Se você estiver usando Linux é claro ;) ):

$ mkdir -p src/{main,test}/{java,resources}


Agora basta dar o comando do Maven para atualiza o projeto para o Eclipse:

$ mvn eclipse:eclipse


Vamos botar a mão na massa agora. Vamos precisar da seguinte estrutura de classes:

Cadastro
CadastroDao
Hibernateinitialize
Principal


E o arquivo XML do Hibernate:

hibernate.cfg.xml


Primeiro, vamos criar a classe Cadastro, que terá a seguinte estrutura:

package br.org.hibernateobject;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;

@Entity
@Table(name = "cadastro")
public class Cadastro {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id_cadastro")
private int id;

@Column(length = 100)
private String nome;

@Lob
private byte[] foto;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public byte[] getFoto() {
return foto;
}

public void setFoto(byte[] foto) {
this.foto = foto;
}

public String getNome() {
return nome;
}

public void setNome(String nome) {
this.nome = nome;
}
}


O segredo pra funcionar esse esquema é o annotation @Lob, que cria um campo no banco de dados do tipo Blob ou Clob. Eu não testei em outros bancos, somente no MySQL, mas creio que essa mesma annotation dá pra ser usada em outros tipos.

Agora vamos criar a classe CadastroDao, onde fará toda a mágica do negócio:

package br.org.hibernateobject;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.swing.JOptionPane;

import org.hibernate.HibernateException;

public class CadastroDao {

public void save(String txt) {
if (txt.equals("") || txt == null) {
JOptionPane.showMessageDialog(null, "Campo obrigatório!");
} else {
try {
String nome = null;
File f = new File(txt);

// Converte o arquivo em um array de bytes
byte[] buffer = new byte[(int) f.length()];
DataInputStream ds = new DataInputStream(new FileInputStream(f));
ds.readFully(buffer);
ds.close();

// Pega o nome do arquivo
nome = f.getName();

Cadastro c = new Cadastro();
c.setNome(nome);
c.setFoto(buffer);

// Finaliza a transacao com o hibernate
Principal.getHi().getSession().save(c);
Principal.getHi().getTx().commit();

JOptionPane.showMessageDialog(null,
"Arquivo cadastrado com sucesso!");
} catch (HibernateException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}


public void get(int id) {
try {
Cadastro c;
c = (Cadastro)Principal.getHi().getSession()
.get(Cadastro.class, id);

String arquivo = "/tmp/" + c.getNome();

FileOutputStream fos = new FileOutputStream(arquivo);
byte[] buffer = c.getFoto();

fos.write(buffer);
fos.flush();
fos.close();

JOptionPane.showMessageDialog(null,
"Arquivo resgatado com sucesso em: " + arquivo);
} catch (HibernateException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}


O método save(String txt) pega o caminho absoluto de onde está o arquivo da foto, depois passa para um DataInputStream que passa para um array de bytes. Feito isso, basta apenas passar para nosso método lá da classe Cadastro setFoto(byte[] foto). O método get(int id) faz o processo contrário, salvando a foto do banco para o diretório /tmp conforme foi setado na variável arquivo.

Vamos criar a classe HibernateInitialize, que vai ser responsável em criar a fábrica de sessão do Hibernate e iniciar as transações:

package br.org.hibernateobject;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;

public class HibernateInitialize {

private Session session;
private Transaction tx;


public HibernateInitialize() {
Configuration cfg = new AnnotationConfiguration()
.addAnnotatedClass(Cadastro.class)
.setProperty(Environment.HBM2DDL_AUTO, "update");

cfg.configure("/br/org/hibernateobject/hibernate.cfg.xml");

SessionFactory sf = cfg.buildSessionFactory();
session = sf.openSession();
tx = session.beginTransaction();
}


public Session getSession() {
return session;
}

public void setSession(Session session) {
this.session = session;
}

public Transaction getTx() {
return tx;
}

public void setTx(Transaction tx) {
this.tx = tx;
}

}


Dispensa comentários. Eu ainda uso XML para configurações, se você usa annotations, pode fazer essa classe do jeito que preferir. O arquivo hibernate.cfg.xml tem a seguinte estrutura:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>
<!-- properties -->
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="connection.url">
jdbc:mysql://localhost:3306/hibernate_object
</property>
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="show_sql">false</property>
<property name="connection.username">hibernate</property>
<property name="connection.password">hibernate123</property>
<property name="connection.pool_size">10</property>
<!-- mapping classes -->
<mapping class="br.org.hibernateobject.Cadastro" />
</session-factory>
</hibernate-configuration>


Agora vamos fazer a classe Principal, que vai ser a interface gráfica e dispensa comentário também. Com uma interface simples usando Swing e chamando os métodos do CadastroDao:

package br.org.hibernateobject;

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class Principal extends JFrame {

private static final long serialVersionUID = 1L;
private static HibernateInitialize hibernate;

public Principal() {
super("Hibernate Salvando Objetos");

setSize(400,100);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);

// Centraliza a janela
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
int w = getSize().width;
int h = getSize().height;
int x = (dim.width-w) / 2;
int y = (dim.height-h) / 2;
setLocation(x, y);

final JTextField txtFoto = new JTextField(30);
final JButton btOK = new JButton("Salvar");
final JButton btGet = new JButton("Resgatar");

// Acao do click do botao
btOK.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {
String txt = txtFoto.getText();
CadastroDao cdao = new CadastroDao();
cdao.save(txt);
}

});

btGet.addActionListener(new ActionListener(){

public void actionPerformed(ActionEvent e) {
int id = Integer.parseInt(JOptionPane
.showInputDialog("Informe o ID do cadastro:"));

CadastroDao cdao = new CadastroDao();
cdao.get(id);
}

});

JPanel p = new JPanel();
p.add(txtFoto);
p.add(btOK);
p.add(btGet);

getContentPane().add(p);
}

public static void main(String[] args) {
new Principal().setVisible(true);
hibernate = new HibernateInitialize();
}


public static HibernateInitialize getHi() {
return hibernate;
}


public static void setHi(HibernateInitialize hi) {
Principal.hibernate = hi;
}
}


Execute o seu programa e digite o caminho completo de algum arquivo de foto e clique no botão Salvar, se aparecer a mensagem 'Arquivo cadastrado com sucesso!', parabéns, senão, verifique seu código.

É isso, espero ter ajudado com esse pequeno conhecimento. O Hibernate é muito poderoso, dá pra fazer muita coisa com ele sem ao menos mexer no banco.

Enjoy...

quarta-feira, 11 de junho de 2008

Controle de banda com TC e IPTABLES

Olá amiguinhos,

Atendendo a pedidos ontem no laboratório, vou fazer um tutorial explicando como controlar a banda usando o tc e o iptables. Vou tentar ser o mais didático possível. Bom, vamos lá, considerando que sua distribuição seja Debian, verifique se o iproute e o tcng estão instalados, caso não estejam, instale com o seguinte comando:

# aptitude install tcng


Agora vá até um diretório qualquer, e crie um script:

# vim fw


Agora monte a seguinte estrutura:

#!/bin/bash

# Linha 1
tc qd del dev eth0 root

# Linha 2
tc qd add dev eth0 root handle 1: htb

# Linha 3
tc cl add dev eth0 parent 1: classid 1:1 htb rate 4Mbit ceil 4Mbit

# Linha 4
tc cl add dev eth0 parent 1:1 classid 1:10 htb \
rate 64Kbit ceil 128Kbit prio 1

# Linha 5
tc filter add dev eth0 parent 1:0 protocol ip prio 1 \
handle 0x1 fw classid 1:10

# Linha 6
iptables -t mangle -F

# Linha 7
iptables -t mangle -A POSTROUTING -p tcp --sport 80 \
-j MARK --set-mark 0x1


Bom, vamos lá vou explicar linha por linha:

# Linha 1: Esse comando apaga a classe raiz do dispositivo eth0. Ou seja, ele apaga tudo mesmo, todas as classes que estão incorporadas na classe raiz. É interessante usar esse comando quando se faz um script que você precisa reiniciar os serviços.

# Linha 2: Adiciona uma nova fila raiz, no dispositivo eth0, com o tipo de fila htb. Esse comando cria o topo da hierarquia, onde tudo vai ser incluído nele.

# Linha 3: Adiciona uma classe mãe, no dispositivo eth0, e ela é parente da classe raiz (1:), o tipo da fila dela é htb e a banda definida para essa classe é de 4Mbit. O comando ceil, é uma variação de banda, significa que se você definir, por exemplo, 1Mbit ceil 4Mbit, o minimo é 1Mbit e o máximo que pode chegar é 4Mbit. Pra simplificar é isso que significa. Agora que criamos a classe mãe, faremos os filhos dela e trabalharemos de acordo com o limite de banda definidos por ela.

# Linha 4: Cria uma classe para o dispositivo eth0, sendo que é parente da classe 1:1 (classe mãe), a identificação dela é 1:10, o tipo da fila dela é htb, e a banda definida para essa classe é de 64Kbit no minimo e 128Kbit no máximo. O parametro prio, é a prioridade, segue o mesmo conceito do TOS. Você pode criar várias classes filho, e você pode brincar com isso, por exemplo, pra http eu defino uma velocidade, pra ssh eu defino outra e assim vai. Eu posso distribuir a banda pra cada tipo de serviço.

# Linha 5: O segredo da coisa funcionar. Essa linha cria um filtro de acordo com a marcação que foi feito no pacote com o iptables. Se você marcar o pacote com o número 0x1, o htb vai pegar esse pacote e tratar conforme a classe pede. Então, cria um filtro para o dispositivo eth0, da classe raiz, sobre o protocolo ip, com prioridade número 1, com todos os pacotes que estejam marcados com o número 0x1, e redireciona para a classe com identificação 1:10 tratar a banda. Simples não?

# Linha 6: Simplesmente limpa a tabela mangle do iptables.

# Linha 7: Marca todos os pacotes que estão saindo pela porta 80 com o número 0x1, de qualquer origem pra qualquer destino, sobre o protocolo tcp.

Essas regras foram adicionadas somente no dispositivo eth0. Se seu servidor usa um modem do tipo router, vai funcionar perfeitamente. Se for um modem que conecta sobre o pppOE, então é só mudar a interface para ppp0.

Trabalhar com o TC não é dificil, basta entender o conceito de hierarquia, veja o desenho abaixo:



Bom, espero que eu consegui ajudar. Qualquer dúvida é só perguntar.

Enjoy...

terça-feira, 10 de junho de 2008

Instalando a placa PCMCIA Netgear WG511 no Debian

Olá amiguinhos.

Eu penei pra conseguir instalar essa placa e consegui depois de dois dias. O maior problema de instalar essa placa, é que a versão do ndiswrapper 1.9 não é compatível, então eu experimentei instalar a versão 1.1 e funcionou perfeitamente. Bom, vamos ao que interessa.

Instale os pacotes do ndiswrapper, com o seguinte comando:

# aptitude install ndiswrapper-utils-1.1 ndiswrapper-source


Depois faça o download do driver da placa neste link:

Download Netgear WG511

Bom, não vou abordar o assunto do driver, mas o processo é o mesmo para instalar os drivers, basta localizar o seu driver no site do ndiswrapper, qualquer dúvida, basta me enviar um e-mail.

Descompacte o pacote em um diretório qualquer e entre nele. Execute os seguintes comandos:

# ndiswrapper -i 2802W.inf
# ndiswrapper -l
installed drivers:
2802w driver installed, hardware (1260:3890) present (alternate driver: prism54)


Se tudo correu bem, vai aparecer que o driver está instalado e caso a placa esteja plugada, ela estara presente também.

Agora é preciso que o módulo prism54 seja removido, pois vai dar conflito na hora de carregar o módulo do ndiswrapper. Faça com o seguinte comando:

# rmmod prism54
# echo blacklist prism54 >> /etc/modprobe.d/blacklist


Carregue o módulo do ndiswrapper:

# modprobe ndiswrapper


Eu tive problemas nesta parte também, ele não encontrava o módulo do ndiswrapper. Então a solução foi instalar o pacote chamado module-assistant. Nele, selecionei o módulo do ndiswrapper e mandei compilar os fonte e instalar. É bem simples que eu nem vou abordar no tutorial.

Depois crie o alias do dispositivo:

# ndiswrapper -m
adding "alias wlan0 ndiswrapper" to /etc/modprobe.d/ndiswrapper...


Adicione o módulo do ndiswrapper no boot:

# echo ndiswrapper >> /etc/modules


Pronto, agora é só dar um dmesg e ver se o kernel identificou a sua placa. No meu apareceu o seguinte:

ndiswrapper: using IRQ 11
wlan0: vendor: 'SMC2802W 2.4GHz 54 Mbps Wireless PCI Adapter'
wlan0: ethernet device 00:0f:b5:5a:77:b1 using NDIS driver 2802w, 1260:3890.5.conf
wlan0: encryption modes supported: WEP; TKIP with WPA; AES/CCMP with WPA
usbcore: registered new driver ndiswrapper


Se aparecer isso, parabéns, sua placa está configurada. Agora basta configurar sua rede wireless.

Enjoy...

segunda-feira, 9 de junho de 2008

Configurando o Squid com o OpenLdap

Olá amiguinhos,

Este tutorial foi feito por mim mesmo e com auxilio ao fórum GDH para tirar dúvidas. Antes de tudo, vou mostrar como se faz no Debian, no CentOS tive muitos problemas, acho que os pacotes do Squid não foram compilados com suporte ao Ldap, e eu fiquei uma semana quebrando a cabeça pra descobrir isso. A solução foi compilar o Squid na mão e assim, funcionou no CentOS. Mas no Debian não tem esse problema, então vamos lá. Primeiro vamos configurar o OpenLdap, instale ele:

# aptitude install ldap-server ldap-client


Após a instalação é preciso ser feito uma configuração básica do openldap:

# cd /etc/ldap
# vim slapd.conf


E altere o arquivo conforme abaixo:

include         /etc/ldap/schema/core.schema
include /etc/ldap/schema/cosine.schema
include /etc/ldap/schema/nis.schema
include /etc/ldap/schema/inetorgperson.schema
pidfile /var/run/slapd/slapd.pid
argsfile /var/run/slapd/slapd.args
loglevel 0
modulepath /usr/lib/ldap
moduleload back_bdb
sizelimit 500
tool-threads 1
backend bdb
checkpoint 512 30
database bdb
suffix "dc=teste,dc=com,dc=br"
directory "/var/lib/ldap"
dbconfig set_cachesize 0 2097152 0
dbconfig set_lk_max_objects 1500
dbconfig set_lk_max_locks 1500
dbconfig set_lk_max_lockers 1500
index objectClass eq
lastmod on
access to attrs=userPassword,shadowLastChange
by dn="cn=admin,dc=teste,dc=com,dc=br" write
by anonymous auth
by self write
by * none
access to dn.base="" by * read
access to *
by dn="cn=admin,dc=teste,dc=com,dc=br" write
by * read


Depois configuramos o ldap.conf conforme abaixo:

BASE dc=teste,dc=com,dc=br
rootbinddn cn=admin,dc=teste,dc=com,dc=br
bindpw {SSHA}7z7N6plyPwijNr2tyhOPpZWc3NMRiKQg
host 127.0.0.1


A senha você pode gerar usando o seguinte comando:

# slappasswd -s teste


Então basta copiar o resultado da senha criptografada e colocar na frente do bindpw.

Feito isso, basta iniciar o serviço do Ldap para começarmos a popular nossa base:

# /etc/init.d/slapd start


Agora vamos criar os arquivos .ldif, que contém os dados para o funcionamento do Squid. É necessário que se siga essa mesma linha lógica da base de dados para não haver erros futuramente. Primeiro, vamos criar o base.ldif, que contém as informações da base principal do ldap. Este é opicional, já que quando você instala pelo aptitude, ele já te pede pra criar a base principal, mas se você quiser excluir ela e começar do zero, fique a vontade. Crie o arquivo base.ldif conforme abaixo:

dn: dc=teste,dc=com,dc=br
objectClass: top
objectClass: dcObject
objectClass: organization
dc: teste
o: Teste Ltda


Feito isso, salve o arquivo para ser adicionado depois. Agora criaremos o arquivo dos grupos, no arquivo grupos.ldif:

dn: ou=usuarios,dc=teste,dc=com,dc=br
ou: usuarios
objectClass: top
objectClass: organizationalUnit
objectClass: dcObject
dc: teste

dn: ou=grupos,dc=teste,dc=com,dc=br
ou: grupos
objectClass: top
objectClass: organizationalUnit
objectClass: dcObject
dc: teste


Agora o arquivo usuarios.ldif:

dn: cn=anderson,ou=usuarios,dc=teste,dc=com,dc=br
objectClass: top
objectClass: person
objectClass: posixAccount
objectClass: inetOrgPerson
cn: anderson
sn: Anderson
mail: teste@teste.com.br
telephonenumber: 1234-5678
uid: anderson
userPassword: 123456
homeDirectory: /home/anderson
displayName: anderson
loginShell: /dev/null
uidNumber:1001
gidNumber:2001

dn: cn=clayton,ou=usuarios,dc=teste,dc=com,dc=br
objectClass: top
objectClass: person
objectClass: posixAccount
objectClass: inetOrgPerson
cn: clayton
sn: Clayton
mail: teste2@teste.com.br
telephonenumber: 9876-5432
uid: clayton
userPassword: teste
homeDirectory: /home/clayton
displayName: clayton
loginShell: /dev/null
uidNumber:1002
gidNumber:2002


Vamos criar o segredo da coisa, que faz o squid saber qual grupo o usuário pertence. Crie um arquivo chamado usuarios_por_grupo.ldif (Obs. O nome dos arquivos não interfere em nada, crie com o nome que quiser):

dn: cn=AuthLiberado,ou=grupos,dc=teste,dc=com,dc=br
objectClass: posixGroup
objectClass: top
memberUid: anderson
cn: AuthLiberado
gidNumber: 3001

dn: cn=AuthBloqueado,ou=grupos,dc=teste,dc=com,dc=br
objectClass: posixGroup
objectClass: top
memberUid: clayton
cn: AuthBloqueado
gidNumber: 3002


Se tiver mais de um usuário, pode adicionar mais memberUid. Feito isso, vamos popular a base do ldap, com o seguinte comando:

ldapadd -f base.ldif -x -D "cn=admin,dc=teste,dc=com,dc=br" -W
ldapadd -f grupos.ldif -x -D "cn=admin,dc=teste,dc=com,dc=br" -W
ldapadd -f usuarios.ldif -x -D "cn=admin,dc=teste,dc=com,dc=br" -W
ldapadd -f usuarios_por_grupo.ldif -x \
-D "cn=admin,dc=teste,dc=com,dc=br" -W


Pronto!!! Se não deu nenhum erro, o OpenLdap está pronto para ser usado com o Squid. Agora vamos para a parte da configuração do Squid.

Configurando o Squid

Vamos instalar o Squid pelo aptitude. Lembrando que se você estiver usando CentOS ou outra distribuição derivada do RedHat e esse tutorial não funcionar, compile o código-fonte do Squid que vai funcionar. Instale o Squid:

# aptitude install squid


Limpe o arquivo de configuração do Squid para facilitar a sua vida:

# egrep -v "^$|^#" squid.conf > squid.conf.limpo
# mv squid.conf.limpo squid.conf


Se o squid ainda não está startado, start ele:

# /etc/init.d/squid start


Beleza, agora deixe o arquivo do squid.conf conforme abaixo:

http_port 3128
hierarchy_stoplist cgi-bin ?
acl QUERY urlpath_regex cgi-bin \?
cache deny QUERY
acl apache rep_header Server ^Apache
broken_vary_encoding allow apache
access_log /var/log/squid/access.log squid
hosts_file /etc/hosts
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern ^gopher: 1440 0% 1440
refresh_pattern . 0 20% 4320
acl all src 0.0.0.0/0.0.0.0
acl manager proto cache_object
acl localhost src 127.0.0.1/255.255.255.255
acl to_localhost dst 127.0.0.0/8
acl SSL_ports port 443 # https
acl SSL_ports port 563 # snews
acl SSL_ports port 873 # rsync
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # https
acl Safe_ports port 70 # gopher
acl Safe_ports port 210 # wais
acl Safe_ports port 1025-65535 # unregistered ports
acl Safe_ports port 280 # http-mgmt
acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http
acl Safe_ports port 631 # cups
acl Safe_ports port 873 # rsync
acl Safe_ports port 901 # SWAT
acl purge method PURGE
acl CONNECT method CONNECT
http_access allow manager localhost
http_access deny manager
http_access allow purge localhost
http_access deny purge
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports

# Autenticacao
auth_param basic program /usr/lib/squid/ldap_auth -D "cn=admin,dc=teste,dc=com,dc=br" -w SENHA -b "dc=teste,dc=com,dc=br" -f "uid=%s" -h 127.0.0.1 -p 389 -v 3
auth_param basic realm Autorização de Acesso
auth_param basic children 5
auth_param basic credentialsttl 2 hours

# Autenticacao por Grupos
external_acl_type ldap_group %LOGIN /usr/lib/squid/squid_ldap_group -b "ou=grupos,dc=teste,dc=com,dc=br" -B "ou=usuarios,dc=teste,dc=com,dc=br" -f "(&(memberUid=%u)(cn=%g))" -h 127.0.0.1 -p 389 -v 3

# Cria a acl para os grupos do ldap
acl Liberado external ldap_group AuthLiberado
acl Bloqueado external ldap_group AuthBloqueado

# Aqui vamos bloquear o acesso para os usuarios que estao no grupo Bloqueados e liberar somente os do Liberado
http_access allow Liberado

http_access deny all

http_reply_access allow all
icp_access allow all
cache_effective_group proxy
coredump_dir /var/spool/squid
visible_hostname teste.com.br
error_directory /usr/share/squid/errors/Portuguese


Lembrando que essas regras, apenas vão liberar o acesso total para a acl Liberado e bloqueando o resto, então brinque a vontade com as regras. Agora reinicie as configurações do Squid, se não der nenhum erro, parabéns:

# squid -k reconfigure


Agora faça o teste. Abra seu navegador favorito, configure o proxy como localhost, e tente acessar algum site. Primeiro teste com o usuário anderson e depois com o usuário clayton e veja o que acontece.

Enjoy...

sábado, 7 de junho de 2008

Configurando o MyGWT/ExtGWT no Eclipse

Olá amiguinhos.

Esse esquema funciona tanto no GWT quanto no MyGWT/ExtGWT. Agradecimentos ao Lucas que me ensinou passo a passo ;-)

Faça o download das bibliotecas em http://mygwt.net e http://code.google.com/webtoolkit/

Descompacte o pacote do GWT e do MyGWT/ExtGWT em algum diretório de sua preferência. E acesse o diretório onde ficou o GWT:

$ cd /exemplo/gwt-linux-1.4.62


Agora é preciso gerar os arquivos de projeto para que funcione corretamente no Eclipse. Basta executar os seguintes comandos:

$ ./applicationCreator -eclipse \
NOME_DO_PROJETO org.algumacoisa.client.HelloWorld \
-out ~/Projetos/NOME_DO_PROJETO


Ele vai gerar os arquivos necessários para o funcionamento do GWT diretamente no diretório do projeto do Eclipse.

Após isto, vamos criar os arquivos de configuração de projeto do Eclipse, com o seguinte comando (Lembrando que ainda estamos no diretório do GWT)

$ ./projectCreator -eclipse NOME_DO_PROJETO -out \
/home/anderson/Projetos/NOME_DO_PROJETO -overwrite


A opção overwrite é opcional, ele sobrescreve arquivos existentes caso existam.

Feito isto, importe o projeto para o Eclipse. E pronto, o GWT está funcionando, de um Run para testar.

Configurando com o MyGWT/ExtGWT

Para fazer o MyGWT/ExtGWT funcionar, após ter feito toda a configuração do GWT, basta adicionar o arquivo .jar do MyGWT (mygwt.jar) no classpath do projeto e adicionar a seguinte linha no arquivo xml que foi gerado pelo gwt, nome semelhante a NOME_DO_PROJETO.gwt.xml. Adicione a seguinte linha:

<inherits name="net.mygwt.ui.MyGWT" />


Essa linha deve ficar antes da tag . Feito isto, basta criar as classes de acordo com a documentação e viva o Java.

Enjoy...

Resolvendo o problema da tela preta no boot do Ubuntu 7.10

Olá amiguinhos.

Quem tem monitor turbo não precisa dessa dica, mas pra um simples mortal como eu, é útil. Achei essa dica em um fórum e vou compartilhar.



Instalei o Ubuntu 7.10, codenome Gutsy Gibbon, no meu notebook e tive uma ingrata surpresa: não aparecia o splash de carregamento do sistema.
Tudo o que eu via era uma tela preta. Tinha pensado que a instalação tinha dado pau, e reinstalei o Ubuntu umas 4 vezes: 2 a versão para 64 bits e mais 2 para a versão X86.
Com todas as reinstalações o problema continuava... Resolvi deixar sistema, recem instalado pela quarta vez, rodar com aquela tela preta. Para minha surpresa o sistema carregou e apareceu a tela de login 'linda de bonita' para mim.
Depois de muito pesquisar, e não achar nada acabei indo no canal de IRC do Ubuntu-br. Lá o pessoal me passou a seguinte dica:

Edite o arquivo upsplash.conf. No terminal digite:

sudo gedit /etc/usplash.conf


Coloque os valores relativos a resolução do seu monitor:

xres=*1024*
yres=*768*


Atenção: Esses valores são relativos á minha tela, não se esqueça de mudá-los!
Salve o arquivo.
Depois, ainda no terminal digite:

sudo update-usplash-theme usplash-theme-ubuntu


Esse comando irá atualizar as configurações que acabamos de mudar. Depois disso reinicie o sistema, e você verá um lindo splash screen do ubuntu carregando o seu sistema.

sexta-feira, 6 de junho de 2008

Como ler um arquivo XML com GWT

Olá amiguinhos.

Considerando o seguinte arquivo XML:


<?xml version="1.0" encoding="UTF-8"?>
<nome id="1">Anderson Clayton</nome>


O XML precisa estar no diretório public da estrutura de diretórios do GWT. Agora para ler esses dados do XML, é simples como falar a palavra "paralelepípedo".


public void onModuleLoad() {
HTTPRequest.asyncGet("nome.xml", new ResponseTextHandler() {

public void onCompletion(String responseText) {
Document customerDom = XMLParser.parse(responseText);
Element customerElement = customerDom.getDocumentElement();
XMLParser.removeWhitespace(customerElement);

// Pega o ID da tag nome
String id = customerElement.getElementsByTagName("nome")
.item(0).getAttributes().getNamedItem("id")
.getNodeValue();
// Pega o valor da tag nome
String nome = customerElement.getElementsByTagName("nome")
.item(0).getNodeValue();

// Exibe os valores
Window.alert(id);
Window.alert(nome);
}

});
}


Fácil né? Você pode fazer um laço para percorrer o XML, é possível pegar o length de cada nó, usando o método getLength().

Enjoy...

quinta-feira, 5 de junho de 2008

Utilizando o Hibernate no GWT

Olá amiguinhos.

Vou mostrar um simples exemplo de como fazer um cadastro no GWT utilizando Hibernate. Eu achei muito trabalhoso pelo fato de não poder utilizar os recursos do Java 5. Mas em breve teremos a possibilidade de utilizar o Java 5 no GWT.

Primeiro, vamos fazer uma interface bem tosca, só com os campos necessários para nosso teste. Detalhe, esse esquema também funciona com o MyGWT, basta mudar os componentes. Vou evitar falar sobre a configuração do Hibernate, eu utilizo xml ainda, então não vou entrar em tantos detalhes.

Crie o projeto do GWT e crie uma classe chamada Principal, como segue abaixo:


package org.cadastrogwt.client;

public class Principal implements EntryPoint {

public void onModuleLoad() {
// Cria o formulario para cadastro
final FormPanel form = new FormPanel();
final VerticalPanel p = new VerticalPanel();
form.setWidget(p);
final Label lbNome = new Label("Nome");
p.add(lbNome);
final TextBox txtNome = new TextBox();
txtNome.setName("txtNome");
p.add(txtNome);
final Label lbCidade = new Label("Cidade");
p.add(lbCidade);
final TextBox txtCidade = new TextBox();
txtCidade.setName("txtCidade");
p.add(txtCidade);

// Cria um botao e define um evento para ele
Button btCadastrar = new Button("Cadastrar");
p.add(btCadastrar);

RootPanel.get().add(form);
}
}



Lembrando que eu não estou me preocupando muito com a aparência, e essa vai ficar muito feia hehe. Após isso, temos que criar as interfaces que vão controlar os dados e trabalhar RPC e a classe de "entidade". Devido ao problema do código do GWT ser compatível com o Java 1.4, vamos ter que duplicar essa classe de entidade no lado do server, com suas devidas annotations. Criamos então a classe Cadastro:


package org.cadastrogwt.client;

import com.google.gwt.user.client.rpc.IsSerializable;

public class Cadastro implements IsSerializable {

private String nome;
private String cidade;
private String estado;

public String getNome() {
return nome;
}

public void setNome(String nome) {
this.nome = nome;
}

public String getCidade() {
return cidade;
}

public void setCidade(String cidade) {
this.cidade = cidade;
}

public String getEstado() {
return estado;
}

public void setEstado(String estado) {
this.estado = estado;
}
}



Depois criamos duas interfaces, uma para o método que retornará alguma coisa do servidor e outra que enviará alguma coisa para o servidor. Simples não? Criamos a interface CadastroService:


package org.cadastrogwt.client;

import com.google.gwt.user.client.rpc.RemoteService;

public interface CadastroService extends RemoteService {
public String cadastrar(Cadastro c);
}



E a interface CadastroServiceAsync:


package org.cadastrogwt.client;

import com.google.gwt.user.client.rpc.AsyncCallback;

public interface CadastroServiceAsync {
public void cadastrar(Cadastro c, AsyncCallback callback);
}



Um detalhe muito importante e que é regra no GWT, apanhei muito no começo pra descobrir isso hehe. Essas duas interfaces, precisam obrigatóriamente conter Service e ServiceAsync nos nomes delas. Então crie um padrão, por exemplo, eu quero trabalhar com a classe Cidadao com o RPC, então eu vou criar as interfaces CidadaoService e CidadaoServiceAsync.

Bom, está quase pronto, agora precisamos criar um pacote no mesmo nível dos pacotes org.cadastrogwt.client e org.cadastrogwt.public. Crie um pacote chamado org.cadastrogwt.server. Tudo que ficar neste pacote é livre pra usar qualquer recurso do Java, Hibernate, Struts, tudo mesmo, pois ele será executado no servidor e não no cliente. Então criamos uma classe chamada CadastroServiceImpl (Mesma regra das interfaces também):


package org.cadastrogwt.server;

import org.cadastrogwt.client.Cadastro;
import org.cadastrogwt.client.CadastroService;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class CadastroServiceImpl extends RemoteServiceServlet
implements CadastroService {

private static final long serialVersionUID = 1L;

public String cadastrar(Cadastro c) {
// Valores definidos pelo cliente
String nome = c.getNome();
String cidade = c.getCidade();
String estado = c.getEstado();
String retorno = null;

// Hibernate
CadastroServerDao cdao = new CadastroServerDao();
cdao.insert(nome, cidade, estado);

retorno = "Cadastro efetuado com sucesso!!!";

return retorno;
}

}



Esta classe pega tudo que foi setado na classe Cadastro e passa para o Dao. Se pudesse usar annotations, eu poderia pegar o objeto c e já mandar para o Dao, mas vamos aguardar a versão 1.5 :)

Bom, agora para dar certo, vamos criar uma classe igual a classe Cadastro, mas mapeando-a. Criamos a classe CadastroServer:


package org.cadastrogwt.server;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "cadastro")
public class CadastroServer {

@Id
@Column(name = "id_cadastro")
private int id;

@Column(length = 100)
private String nome;

@Column(length = 50)
private String cidade;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getNome() {
return nome;
}

public void setNome(String nome) {
this.nome = nome;
}

public String getCidade() {
return cidade;
}

public void setCidade(String cidade) {
this.cidade = cidade;
}
}



Beleza, agora é só criar o Dao. Criamos a classe CadastroServerDao:


package org.cadastrogwt.server;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;

public class CadastroServerDao {

private Session session;
private Transaction tx;

public CadastroServerDao() {
Configuration cfg = new AnnotationConfiguration();
cfg.configure("/org/cadastrogwt/server/hibernate.cfg.xml");

SessionFactory sf = cfg.buildSessionFactory();

session = sf.openSession();
tx = session.beginTransaction();
}


public void insert(String nome, String cidade, String estado) {
CadastroServer cad = new CadastroServer();
cad.setCidade(cidade);
cad.setEstado(estado);
cad.setNome(nome);

session.save(cad);
tx.commit();
session.close();
}

}



Fica a critério de cada um como usar o Configuration. Pronto, a parte do server está pronta. Agora vamos voltar para a parte do client novamente, para preparar a classe Principal para trabalhar com o AsyncCallback que faz a mesma coisa que o Ajax. Modifique a classe Principal para que fique com a mesma aparência que esta:


package org.cadastrogwt.client;

import *****;

public class Principal implements EntryPoint, AsyncCallback {

private CadastroServiceAsync service;

private void asyncCadastro(Cadastro c) {
this.service.cadastrar(c, this);
}

public void onModuleLoad() {
// Inicia a sincronizacao com o servlet
service = (CadastroServiceAsync)
GWT.create(CadastroService.class);
ServiceDefTarget target = (ServiceDefTarget) service;
target.setServiceEntryPoint(GWT.getModuleBaseURL() +
"cadastro");

// Cria o formulario para cadastro
final FormPanel form = new FormPanel();
final VerticalPanel p = new VerticalPanel();
form.setWidget(p);
final Label lbNome = new Label("Nome");
p.add(lbNome);
final TextBox txtNome = new TextBox();
txtNome.setName("txtNome");
p.add(txtNome);
final Label lbCidade = new Label("Cidade");
p.add(lbCidade);
final TextBox txtCidade = new TextBox();
txtCidade.setName("txtCidade");
p.add(txtCidade);

// Cria um botao e define um evento para ele
Button btCadastrar = new Button("Cadastrar",
new ClickListener() {
public void onClick(Widget sender) {
Cadastro cad = new Cadastro();
cad.setCidade(txtCidade.getText());
cad.setNome(txtNome.getText());

asyncCadastro(cad);
}
});
p.add(btCadastrar);

RootPanel.get().add(form);
}

public void onFailure(Throwable caught) {
// Joga uma mensagem de erro caso ocorra
Window.alert(caught.getMessage());
}

public void onSuccess(Object result) {
// Retorna a resposta do servidor
Window.alert(result.toString());
}
}



Pronto, agora antes de testar, é necessário criar uma linha no xml do projeto GWT, que seria Principal.gwt.xml. Adicione depois da tag entry-point:



<servlet path="/cadastro"
class="org.cadastrogwt.server.CadastroServiceImpl" />



Pronto, rode o projeto e tente fazer um cadastro e depois olhe no banco de dados se foi corretamente. Eu não vou explicar como faz a listagem, porque seria legal se desse pra retornar do servidor um ArrayList mas não consegui, vou fazer mais testes. Mas fica ae pra diversão de vocês. Usei como base os exemplos que vem no pacote do GWT, lá tem o pacote DynamTable que usa recursos do RPC.

Enjoy...