Example description: I have to create a custom group store so I could add them to the groups retrieved from LDAP. My choice is storing them in XML files. So I thought someone might find my experience interesting.
Prerequisites: Eclipse for java development with m2e plugin.
Create XSD file
Why? This will make creating XML files very easy and will ensure that those files will be readable as expected. I won't go into details, since it's not so hard to create even very complex schema definition files. But here's the result (file /src/main/resources/lv/rtu/itd/vivs/user-groups-1.0.xsd):
<schema elementformdefault="qualified" targetnamespace="http://vivs.rtu.lv/schemas/user-groups" xmlns:tns="http://vivs.rtu.lv/schemas/user-groups" xmlns="http://www.w3.org/2001/XMLSchema">
<element name="user-groups" type="tns:user-groups-type">
<complextype name="user-groups-type">
<sequence>
<element maxoccurs="unbounded" name="user-groups" type="tns:user-group" />
</sequence>
</complextype>
<complextype name="user-group">
<sequence>
<element name="uid" type="string" />
<element maxoccurs="unbounded" name="group" type="string" />
</sequence>
</complextype>
</element>
Configure class generation
Create file src/main/binding/bindings.xjb (this will instruct the generator how to create new classes):
<bindings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
version="2.1">
<bindings>
<globalBindings>
<serializable uid="1" />
<xjc:simple />
</globalBindings>
</bindings>
<bindings schemaLocation="../resources/lv/rtu/itd/vivs/user-groups-1.0.xsd">
<schemaBindings>
<package name="lv.rtu.itd.vivs.xml.user_groups" />
</schemaBindings>
</bindings>
</bindings>
Configure pom.xml and add something like this in order to tell Maven that it must now generate classes using jaxb2:
<build>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.7.4</version>
<executions>
<execution>
<id>generate-xjc-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<bindingDirectory>src/main/binding</bindingDirectory>
<schemaDirectory>src/main/resources</schemaDirectory>
<schemaIncludes>
<include>lv/rtu/itd/vivs/*.xsd</include>
</schemaIncludes>
<extension>true</extension>
<args>
<arg>-no-header</arg>
<arg>-readOnly</arg>
<arg>-mark-generated</arg>
</args>
</configuration>
<dependencies>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-xjc</artifactId>
<version>2.2.1</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
Now, probably, you must click on project and choose Maven > Update Project Configuration
Java code
Create interface for class:
package lv.rtu.itd.vivs.service;
import java.util.Set;
public interface GroupService {
Set getGroups(String uid);
}
Create class that will unmarshal (read) the XML document:
package lv.rtu.itd.vivs.service.impl;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import lv.rtu.itd.vivs.service.GroupService;
import lv.rtu.itd.vivs.xml.user_groups.UserGroup;
import lv.rtu.itd.vivs.xml.user_groups.UserGroups;
public class XmlGroupService implements GroupService {
private Logger logger = LoggerFactory.getLogger(getClass());
private UserGroups groups;
public void setFilename(String filename) {
JAXBContext ctx;
try {
ctx = JAXBContext.newInstance("lv.rtu.itd.vivs.xml.user_groups");
Unmarshaller unmarshaller = ctx.createUnmarshaller();
InputStream is = new ClassPathResource(filename).getInputStream();
this.groups = (UserGroups) unmarshaller.unmarshal(is);
} catch (JAXBException e) {
logger.warn(e.getMessage(), e);
} catch (IOException e) {
logger.warn(e.getMessage(), e);
}
}
@Override
public Set getGroups(String uid) {
for (UserGroup group : groups.getUserGroups()) {
if (group.getUid().equals(uid)) {
return new HashSet(group.getGroups());
}
}
return new HashSet();
}
}
Create test class (under src/test/java):
package lv.rtu.itd.vivs.service;
import java.util.HashSet;
import java.util.Set;
import lv.rtu.itd.vivs.service.impl.XmlGroupService;
import org.junit.Assert;
import org.junit.Test;
public class XmlGroupsTester {
@Test()
public void testGetGroups() {
XmlGroupService service = new XmlGroupService();
service.setFilename("user-groups.xml");
Set expected = new HashSet();
Assert.assertEquals(expected, service.getGroups("not-existing-user"));
expected.add("my/demo/group");
expected.add("my/demo/group2");
expected.add("my/demo/group3");
Assert.assertEquals(expected, service.getGroups("user.demo"));
}
}
Now create XML file (src/test/resources/user-groups.xml:
<?xml version="1.0" encoding="UTF-8"?>
<user-groups xmlns="http://vivs.rtu.lv/schemas/user-groups" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://vivs.rtu.lv/schemas/user-groups http\://vivs.rtu.lv/schemas/user-groups">
<user-groups>
<uid>user.demo</uid>
<group>my/demo/group</group>
<group>my/demo/group2</group>
<group>my/demo/group3</group>
</user-groups>
</user-groups>
Now you can run tests and check the results.