Developer's Guide


The student teacher repository

This section will include code for implementing a simple XML-based repository. The content of the repository is contained in an XML file that is processed using a SAX parser. The implementation consists only of two Java classes: a file used to represent the entities of the XML content, and a SAX parser used to load in the XML content into memory.

Before implementing the Java classes, create a file called data.xml under org.eclipse.cosmos.example.mdr/src. The content of the file appears below:

<?xml version="1.0" encoding="UTF-8"?>
<school>
	<student>
	 <identity firstName="Bob" lastName="Davidson" id="01"/>
	</student>
	
	<student>
	 <identity firstName="Jane" lastName="Ryerson" id="02"/>
	</student>
	
	<student>
	 <identity firstName="Mike" lastName="Lee" id="03"/>
	</student>
	
	<teacher>
	 <identity firstName="Dawn" lastName="Johnson" id="staff01"/>
	</teacher>
	
	<teacher>
	 <identity firstName="Heather" lastName="Reeba" id="staff02"/>
	</teacher>
			
	<class name="Economics" courseCode="ECM01">
	 <students>
	  <enrolledStudent idRef="01"/>
	  <enrolledStudent idRef="03"/>
	 </students>
	 <teacher idRef="staff01"/>
	</class>
	
	<class name="Mathematics" courseCode="MAT01">
	 <students>
	  <enrolledStudent idRef="01"/>
	  <enrolledStudent idRef="02"/>
	 </students>
	 <teacher idRef="staff02"/>
	</class>
	
	<class name="Physics" courseCode="PHY01">
	 <students>
	  <enrolledStudent idRef="02"/>
	  <enrolledStudent idRef="03"/>
	 </students>
	 <teacher idRef="staff02"/>
	</class>	
</school>

Notice the file contains three students, two teachers, and three classes. Each student and teacher element defines a unique ID using the 'id' attribute and each class indicates the teacher and the enrolled students using the id field.

Let's now create the classes that will load in the data above. Create the following two classes under src/org.eclipse.cosmos.example.mdr.handlers.

  1. XMLRepository
  2. SchoolXMLHandler

The first file provides an object representation of the entities in data.xml (i.e. student, teacher, and class). The content of XMLRepository appears below.

package org.eclipse.cosmos.example.mdr.handlers;
 
import java.io.IOException;
import java.io.StringWriter;
 
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
 
import org.eclipse.cosmos.dc.provisional.cmdbf.services.common.CMDBfServicesUtil;
import org.eclipse.cosmos.dc.provisional.cmdbf.services.common.IXMLWritable;
import org.eclipse.cosmos.dc.provisional.cmdbf.services.query.transform.response.artifacts.IItemConvertible;
import org.eclipse.cosmos.dc.provisional.cmdbf.services.query.transform.response.artifacts.INodes;
import org.eclipse.cosmos.dc.provisional.cmdbf.services.query.transform.response.artifacts.IRelationshipConvertible;
import org.eclipse.cosmos.dc.provisional.cmdbf.services.query.transform.response.artifacts.QueryOutputArtifactFactory;
import org.eclipse.cosmos.dc.provisional.cmdbf.services.transform.artifacts.IGraphElement;
import org.eclipse.cosmos.dc.provisional.cmdbf.services.transform.artifacts.IGraphElementCollection;
import org.eclipse.cosmos.dc.provisional.cmdbf.services.transform.artifacts.IItem;
import org.eclipse.cosmos.dc.provisional.cmdbf.services.transform.artifacts.IRecord;
import org.eclipse.cosmos.dc.provisional.cmdbf.services.transform.artifacts.IRelationship;
import org.xml.sax.SAXException;
 
/**
 * This class represents a simple repository that is populated
 * by the data stored in a static XML file.  An implementation of
 * IDataProvider is used to provide a binding to an underlying
 * repository.
 */
public class XMLRepository
{
	/**
	 * The MDR ID
	 */
	public static final String MDR_ID = "org.eclipse.cosmos.samples.cmdbf.XMLRepository";
	
	/**
	 * The XML file that stores the data
	 */
	private static final String XML_DATA = "data.xml";
	
	/**
	 * The namespace of the data
	 */
	private static final String SCHOOL_NAMESPACE = "http://school";
	
	/**
	 * The students of the school
	 */
	public Student[] students;
	
	/**
	 * The teachers of the school
	 */
	public Teacher[] teachers;
	
	/**
	 * The classes of the school
	 */
	public ClassSession[] classes;
	
	
	/**
	 * Constructor
	 * 
	 * @throws ParserConfigurationException 
	 * @throws IOException 
	 * @throws SAXException 
	 */
	public XMLRepository() throws ParserConfigurationException, SAXException, IOException
	{			
		// Read in the XML file and populate fields accordingly
		SchoolXMLHandler schoolXMLHandler = new SchoolXMLHandler();
		SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();		
		saxParserFactory.newSAXParser().parse(XMLRepository.class.getClassLoader().getResourceAsStream(XML_DATA), schoolXMLHandler);		
		
		students = schoolXMLHandler.getStudents();
		teachers = schoolXMLHandler.getTeachers();
		classes = schoolXMLHandler.getSchoolClasses();
	}
	
	
	/**
	 * Represents an identity, which is consisted
	 * of a first name, last name, and an id.
	 */
	public static class Identity
	{
		public String firstName;
		public String lastName;
		public String id;
	}
	
	/**
	 * An abstract class representing a school 
	 * member
	 */
	public abstract static class SchoolMember implements IItemConvertible, IXMLWritable
	{
		public Identity identity = new Identity();		
		
		public IItem toItem(INodes parent)
		{
			IItem item = QueryOutputArtifactFactory.getInstance().createItem();			
			item.addInstanceId(QueryOutputArtifactFactory.getInstance().createInstanceId(MDR_ID, identity.id));
			IRecord record = QueryOutputArtifactFactory.getInstance().createRecord(item, identity.id);
			record.addNamespace("", SCHOOL_NAMESPACE);
			record.setValue(this);
			item.addRecord(record);
			return item;
		}
		
		private static String valueWithIndent(int indent, String value) 
		{
			String tempValue = value;
			StringWriter tabsWriter = new StringWriter();		
			tabsWriter.append('\n');
			CMDBfServicesUtil.addIndent(tabsWriter, indent);				
			tempValue = tempValue.replace("\n", tabsWriter.toString());
			tempValue = tabsWriter.toString() + tempValue;
			return tempValue;
		}
		
		public void toXML(StringWriter writer, int indentLevel)
		{
			StringBuffer buffer = new StringBuffer();
			buffer.append ("<" + getElementName() + ">\n");
			buffer.append (" <identity firstName=\"" + identity.firstName + "\" lastName=\"" + identity.lastName + "\" id=\"" + identity.id + "\"/>\n");
			buffer.append ("</" + getElementName() + ">");
			writer.write(SchoolMember.valueWithIndent(indentLevel, buffer.toString()) + "\n\n");
		}
 
		protected abstract String getElementName();
	}
	
	/**
	 * Represents a student
	 */
	public static class Student extends SchoolMember
	{
		@Override
		protected String getElementName()
		{
			return "student";
		}
 
	}
	
	/**
	 * Represents a teacher of a school
	 */
	public static class Teacher extends SchoolMember
	{
		@Override
		protected String getElementName()
		{
			return "teacher";
		}
	}
	
	/**
	 * Represents a class with enrolled students
	 * and a teacher
	 */
	public static class ClassSession implements IItemConvertible, IRelationshipConvertible, IXMLWritable
	{
		public Student[] students;
		public Teacher teacher;
		public String name;
		public String courseCode;
		public IItem toItem(INodes parent)
		{
			IItem item = QueryOutputArtifactFactory.getInstance().createItem();
			item.addRecord(createRecord(item));
			return item;
		}
		
		
		public IRelationship toRelationship(IGraphElementCollection parent)
		{
			IRelationship relationship = QueryOutputArtifactFactory.getInstance().createRelationship();
			relationship.addInstanceId(QueryOutputArtifactFactory.getInstance().createInstanceId(MDR_ID, courseCode));
			relationship.addRecord(createRecord(relationship));			
			return relationship;
		}
		
		private IRecord createRecord(IGraphElement parent)
		{
			IRecord record = QueryOutputArtifactFactory.getInstance().createRecord(parent, courseCode);
			record.addNamespace("", SCHOOL_NAMESPACE);
			record.setValue(this);
			return record;
		}
 
 
		public void toXML(StringWriter writer, int indentLevel)
		{
			StringBuffer buffer = new StringBuffer();
			buffer.append("<class name=\"" + name + "\" courseCode=\"" + courseCode + "\">\n");
			buffer.append(" <students>\n");
			for (int i = 0; i < students.length; i++)
			{
				buffer.append("  <enrolledStudent idRef=\"" + students[i].identity.id + "\"/>\n");
			}
			buffer.append(" </students>\n");
			buffer.append(" <teacher idRef=\"" + teacher.identity.id + "\"/>\n");
			buffer.append("</class>");
			
			writer.write(SchoolMember.valueWithIndent(indentLevel, buffer.toString()) + "\n\n");
		}
	}
}

The second file is a SAX handler required for loading data.xml into memory. The content of SchoolXMLHandler appears below.

package org.eclipse.cosmos.example.mdr.handlers;
 
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
 
import org.eclipse.cosmos.example.mdr.handlers.XMLRepository.ClassSession;
import org.eclipse.cosmos.example.mdr.handlers.XMLRepository.Identity;
import org.eclipse.cosmos.example.mdr.handlers.XMLRepository.Student;
import org.eclipse.cosmos.example.mdr.handlers.XMLRepository.Teacher;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
 
/**
 * The XML handler for parsing the data that represents 
 * a school with students, teacher, and classes 
 */
public class SchoolXMLHandler extends DefaultHandler
{
	private Student currentStudent;
	private Teacher currentTeacher;
	private ClassSession currentClass;
	private List<Student> enrolledStudents;
	
	private Map<String, Student> students;
	private Map<String, Teacher> teachers;
	private List<ClassSession> classes;
	
	public SchoolXMLHandler()
	{
		students = new Hashtable<String, Student>();
		teachers = new Hashtable<String, Teacher>();
		classes = new ArrayList<ClassSession>();
		enrolledStudents = new ArrayList<Student>();
	}
	
	@Override
	public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException
	{
		if ("student".equals(name))
		{
			currentStudent = new Student();			
		}
		else if ("teacher".equals(name) && currentClass == null)
		{
			currentTeacher = new Teacher();			
		}
		else if ("class".equals(name))
		{
			currentClass = new ClassSession();
			currentClass.name = attributes.getValue("name");
			currentClass.courseCode = attributes.getValue("courseCode");
		}
		else if ("identity".equals(name))
		{
			Identity identity = currentStudent != null ? 
					currentStudent.identity : currentTeacher.identity;
			
			identity.firstName = attributes.getValue("firstName");
			identity.lastName = attributes.getValue("lastName");
			identity.id = attributes.getValue("id");			
		}
		else if ("enrolledStudent".equals(name))
		{			
			enrolledStudents.add(students.get(attributes.getValue("idRef")));
		}
		else if ("teacher".equals(name))
		{
			currentClass.teacher = teachers.get(attributes.getValue("idRef"));
		}
		
	}
	
	@Override
	public void endElement(String uri, String localName, String name) throws SAXException
	{
		if ("student".equals(name))
		{
			students.put(currentStudent.identity.id, currentStudent);
			currentStudent = null;
		}
		else if ("teacher".equals(name) && currentClass == null)
		{
			teachers.put(currentTeacher.identity.id, currentTeacher);
			currentTeacher = null;
		}
		else if ("class".equals(name))
		{
			currentClass.students = enrolledStudents.toArray(new Student[enrolledStudents.size()]);
			classes.add (currentClass);			
			currentClass = null;
			enrolledStudents.clear();
		}
	}
	
	public Student[] getStudents()
	{
		return students.values().toArray(new Student[students.size()]); 
	}
	
	public Teacher[] getTeachers()
	{
		return teachers.values().toArray(new Teacher[teachers.size()]);
	}
	
	public ClassSession[] getSchoolClasses()
	{
		return classes.toArray(new ClassSession[classes.size()]);
	}
}

This concludes implementing the simple XML repository. The next section will describe how the repository can be extended to provide CMDBf query support.


[ Top of Page | Previous Page | Next Page | Table of Contents | Index ]