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...