here i created a java ee 6 based web application to perform CRUD operation on weblogic embedded ldap. JSF 2.0 and Spring ldapTemplate has been used.
the applicationContext.xml is the same as described in my previous post on weblogic embedded ldap. injection of Spring ldapTemplate via CDI is also similar to that post.
lets look at the codes as they speak a lot more than normal explanation,
the model person is a simple pojo
package model;
import java.io.Serializable;
import javax.inject.Named;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotEmpty;
/**
* @author nayef
*/
@Named
public class Person implements Serializable {
@NotEmpty(message = "the uid cant be empty")
private String uid;
@NotEmpty(message = "full name cant be empty")
@Size(max =20, min =5, message="you must provide a full name between 5 to 20 characters")
private String fullName;
@NotEmpty(message = "short name cant be empty")
@Size(max =10, min =3, message="you must provide a short name between 3 to 10 characters")
private String shortName;
@NotEmpty(message = "the password cant be empty")
private String password;
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getShortName() {
return shortName;
}
public void setShortName(String shortName) {
this.shortName = shortName;
}
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
@Override
public String toString() {
return "Person{" + "uid=" + uid + ", fullName=" + fullName + ", shortName=" + shortName + '}';
}
}
the index page contains links of all the other pages,
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>starting page</title>
</h:head>
<h:body>
to create go to <h:link value="create page" outcome="create" />
<br/>
to search go to <h:link value="search page" outcome="search" />
<br/>
for list go to <h:link value="list page" outcome="list" />
</h:body>
</html>
the create.xhtml contains a simple form to create
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<head>
<title>create person</title>
</head>
<body>
<h:form>
<h:outputLabel value="Enter UID " />
<h:inputText value="#{personController.person.uid}" />
<br/>
<h:outputLabel value="Enter Full Name" />
<h:inputText value="#{personController.person.fullName}" />
<br />
<h:outputLabel value="Enter short Name" />
<h:inputText value="#{personController.person.shortName}" />
<br/>
<h:outputLabel value="Enter password" />
<h:inputSecret value="#{personController.person.password}" />
<br/>
<h:commandButton value="Create" action="#{personController.createPerson}" />
<h:commandButton value="Cancel" action="#{personController.cancel}" immediate="true"/>
</h:form>
<br/>
start page <h:link value="start page" outcome="index" />
<br/>
</body>
</html>
the modify.xhtml is like the following. it contains both options for update and delete.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<head>
<title>modify person</title>
</head>
<body>
<h:form id="modifyForm">
<h:outputLabel value="Enter UID " />
<h:outputText value="#{personController.person.uid}" />
<br/>
<h:outputLabel value="Enter Full Name" />
<h:inputText value="#{personController.person.fullName}" />
<br />
<h:outputLabel value="Enter short Name" />
<h:inputText value="#{personController.person.shortName}" />
<br />
<br/>
<h:outputLabel value="previous password" />
<h:inputSecret id="previousPassword" validator="#{personController.passwordValidator}" required="true">
</h:inputSecret>
<br/>
<h:outputLabel value="Enter password" />
<h:inputSecret value="#{personController.person.password}" />
<br/>
<h:commandButton value="Modify" action="#{personController.updatePerson}" />
<br/>
<h:commandButton value="Delete" action="#{personController.deletePerson}" immediate="true"/>
<br/>
<h:commandButton value="Cancel" action="#{personController.cancel}" immediate="true"/>
</h:form>
</body>
</html>
the list.xhtml lists all the entries and gives option to load entries for modification
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>person list</title>
</head>
<body>
<h:form>
<h:dataTable value="#{personController.personList}" var="personElement">
<h:column>
#{personElement.uid}
</h:column>
<br/>
<h:column>
#{personElement.fullName}
</h:column>
<br/>
<h:column>
#{personElement.shortName}
</h:column>
<br/>
<h:column>
<h:commandLink action="#{personController.loadPersonFromList(personElement.uid)}" value="load">
</h:commandLink>
</h:column>
</h:dataTable>
</h:form>
<br/>
to create go to <h:link value="create page" outcome="create" />
<br/>
start page <h:link value="start page" outcome="index" />
</body>
</html>
the search.xhtml lets you search entries using uid.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Search</title>
</head>
<body>
<h:form>
<h:outputLabel value="Enter your uid" />
<h:inputText value="#{personController.searchUid}" />
<h:commandButton value="Submit"
action="#{personController.loadPerson}" />
</h:form>
<br/>
start page <h:link value="start page" outcome="index" />
</body>
</html>
failure notification page,
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<head>
<title>failed</title>
</head>
<body>
<h1>failed</h1>
<br/>
start page <h:link value="start page" outcome="index" />
</body>
</html>
the controller for this CRUD operation is as follows,
package Controller;
import Dao.PersonDaoImpl;
import java.io.Serializable;
import java.util.List;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.ValidatorException;
import javax.inject.Inject;
import javax.inject.Named;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import model.Person;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;
/**
*
* @author nayef
*/
@Named
@ConversationScoped
public class PersonController implements Serializable {
@Valid
@NotNull
private Person person = new Person();
@NotNull
String searchUid;
@Inject
private PersonDaoImpl dao;
@Inject
private Conversation conversation;
@Inject
private LdapTemplate ldapTemplate;
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public String getSearchUid() {
return searchUid;
}
public void setSearchUid(String searchUid) {
this.searchUid = searchUid;
}
public LdapTemplate getLdapTemplate() {
return ldapTemplate;
}
public void setLdapTemplate(LdapTemplate ldapTemplate) {
this.ldapTemplate = ldapTemplate;
}
public List<Person> getPersonList() {
List<Person> personList = dao.findAll();
return personList;
}
public String createPerson() {
try {
dao.create(person);
} catch (Exception e) {
return "actionFailed?faces-redirect=true";
}
return "list?faces-redirect=true";
}
public String loadPerson() {
beginConversation();
try {
Person tempPerson = dao.findPersonByUid(searchUid);
this.person = tempPerson;
} catch (Exception e) {
endConversation();
if (e instanceof org.springframework.ldap.NameNotFoundException) {
} else {
System.out.println(e.toString());
}
return "actionFailed?faces-redirect=true";
}
return "modify?faces-redirect=true";
}
public String updatePerson() {
try {
dao.updatePersonByUid(this.getPerson());
} catch (Exception e) {
endConversation();
return "actionFailed?faces-redirect=true";
}
endConversation();
return "list?faces-redirect=true";
}
public String loadPersonFromList(String uid) {
beginConversation();
try {
Person tempPerson = dao.findPersonByUid(uid);
this.person = tempPerson;
} catch (Exception e) {
conversation.end();
endConversation();
return "actionFailed?faces-redirect=true";
}
return "modify?faces-redirect=true";
}
public String deletePerson() {
try {
dao.deletePersonByUid(this.getPerson());
} catch (Exception e) {
endConversation();
return "actionFailed?faces-redirect=true";
}
endConversation();
return "list?faces-redirect=true";
}
public String loadPersonList() {
endConversation();
return "list?faces-redirect=true";
}
public String cancel() {
endConversation();
return "index?faces-redirect=true";
}
public void passwordValidator(FacesContext context, UIComponent toValidate, Object value) {
String uid = this.getPerson().getUid();
String password = (String) value;
if (password == null || password.trim().length() < 1) {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
"previous Password cant be empty", "previous Password cant be empty");
throw new ValidatorException(message);
}
if (!loginExistsInLdap(uid, password.trim())) {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
"previous password not correct", "previous password not correct");
throw new ValidatorException(message);
}
}
public boolean loginExistsInLdap(String uid, String password) {
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectclass", "person")).and(new EqualsFilter("uid", uid));
boolean legit = false;
try {
legit = this.ldapTemplate.authenticate(DistinguishedName.EMPTY_PATH, filter.toString(), password);
} catch (Exception e) {
legit = false;
}
return legit;
}
private void beginConversation() {
if (conversation.isTransient()) {
conversation.begin();
}
}
private void endConversation() {
if (!conversation.isTransient()) {
conversation.end();
}
}
}
the dao layer is like this
package Dao;
import java.util.List;
import model.Person;
/**
*
* @author nayef
*/
public interface PersonDao {
public void create(Person p);
public void updatePersonByUid(Person p);
public void delete(Person p);
public Person findPersonByUid(String uid);
public List<Person> findAll();
}
dao layer implementation uses spring LdapTemplate for ldap operations
package Dao;
import java.io.Serializable;
import java.util.List;
import javax.inject.Inject;
import javax.naming.Name;
import model.Person;
import org.springframework.ldap.core.ContextMapper;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.EqualsFilter;
/**
*
* @author nayef
*/
public class PersonDaoImpl implements PersonDao, Serializable {
@Inject
private LdapTemplate ldapTemplate;
public void setLdapTemplate(LdapTemplate l) {
ldapTemplate = l;
}
@Override
public void create(Person p) {
DirContextAdapter context = new DirContextAdapter();
mapToContext(p, context);
ldapTemplate.bind(buildDn(p), context, null);
}
@Override
public void delete(Person p) {
ldapTemplate.unbind(buildDn(p));
}
@Override
public List<person> findAll() {
EqualsFilter filter = new EqualsFilter(
"objectclass", "person");
return ldapTemplate.search(
DistinguishedName.EMPTY_PATH,
filter.encode(), getContextMapper());
}
@Override
public void updatePersonByUid(Person person) {
DistinguishedName dn = new DistinguishedName();
dn.add("ou", "people");
dn.add("uid", person.getUid());
DirContextAdapter context = (DirContextAdapter) ldapTemplate.lookup(dn);
mapToContext(person, context);
ldapTemplate.modifyAttributes(dn, context.getModificationItems());
}
@Override
public Person findPersonByUid(String uid) {
DistinguishedName dn = new DistinguishedName();
dn.add("ou", "people");
dn.add("uid", uid);
return (Person) ldapTemplate.lookup(dn, getContextMapper());
}
public void deletePersonByUid(Person person) {
DistinguishedName dn = new DistinguishedName();
dn.add("ou", "people");
dn.add("uid", person.getUid());
ldapTemplate.unbind(dn);
}
protected ContextMapper getContextMapper() {
return new PersonContextMapper();
}
protected Name buildDn(Person p) {
DistinguishedName dn = new DistinguishedName();
dn.add("ou", "people");
dn.add("uid", p.getUid());
return dn;
}
protected void mapToContext(Person p, DirContextAdapter context) {
context.setAttributeValues("objectclass", new String[]{"top",
"person", "inetOrgPerson", "organizationalPerson", "wlsuser"});
context.setAttributeValue("cn", p.getFullName());
context.setAttributeValue("sn", p.getShortName());
context.setAttributeValue("uid", p.getUid());
context.setAttributeValue("userPassword", p.getPassword());
}
private static class PersonContextMapper implements ContextMapper {
@Override
public Object mapFromContext(Object ctx) {
DirContextAdapter context = (DirContextAdapter) ctx;
Person p = new Person();
p.setFullName(context.getStringAttribute("cn"));
p.setShortName(context.getStringAttribute("sn"));
p.setUid(context.getStringAttribute("uid"));
return p;
}
}
}
References
1. https://blogs.oracle.com/jamesbayer/entry/look_inside_weblogic_server_em
2. http://today.java.net/pub/a/today/2006/04/18/ldaptemplate-java-ldap-made-simple.html
3. http://www.jayway.com/2009/02/02/simple-authentication-using-spring-ldap/