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 { SetgetGroups(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 SetgetGroups(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"); Setexpected = 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.