Index: Dev/branches/jos-branch/server/api.php
===================================================================
--- Dev/branches/jos-branch/server/api.php	(revision 308)
+++ Dev/branches/jos-branch/server/api.php	(revision 310)
@@ -4,5 +4,7 @@
 ini_set('display_errors', True);
 
+define("RDFAPI_INCLUDE_DIR", "rdfapi/");
 require_once 'tonic/lib/tonic.php';
+require_once 'classes/Model.php';
 require_once 'classes/master.php';
 
@@ -13,5 +15,5 @@
 
 function set_session_cookie($response, $user) {
-    $response->addHeader('Set-Cookie', 'rft_uid=' . $user->uid . '; Max-Age: 3600; Path=' . $response->request->baseUri);
+    $response->addHeader('Set-Cookie', 'rft_uid=' . $user->getUid() . '; Max-Age: 3600; Path=' . $response->request->baseUri);
 }
 
@@ -87,5 +89,5 @@
 class DataCollectionResource extends Resource {
 
-    function getType($request) {
+    private function getTypeAndUid($request) {
         $uri = get_clean_uri($request);
         $path = explode('/', $uri);
@@ -202,7 +204,5 @@
             $object->$key = $val;
         }
-        if (!$object->save()) {
-            throw new ResponseException("Save failed", Response::INTERNALSERVERERROR);
-        }
+        $object->save();
 
         $response->body = $object;
Index: Dev/branches/jos-branch/server/classes/Auth.php
===================================================================
--- Dev/branches/jos-branch/server/classes/Auth.php	(revision 308)
+++ Dev/branches/jos-branch/server/classes/Auth.php	(revision 310)
@@ -7,13 +7,16 @@
     public static function register($email, $password) {
         $user_results = User::get(array("email" => $email));
-        if ( !empty($user_results) ) {
+        if (!empty($user_results)) {
             throw new Exception("User with email $email already exists.");
         }
         $salt = rand();
-        $user = new User(null,$email,sha1($password.$salt),$salt);
+        $user = new User(null, array(
+                    'email' => $email,
+                    'passwordHash' => sha1($password . $salt),
+                    'passwordSalt' => $salt));
         $user->save();
         return $user;
     }
-    
+
     public static function login($email, $password) {
         $user_results = User::get(array("email" => $email));
@@ -22,5 +25,5 @@
         }
         $user = $user_results[0];
-        if (sha1($password.$user->passwordSalt) != $user->passwordHash) {
+        if (sha1($password . $user->passwordSalt) != $user->passwordHash) {
             throw new Exception("Wrong password.");
         }
@@ -35,5 +38,5 @@
         return $user_results[0];
     }
-    
+
 }
 
Index: Dev/branches/jos-branch/server/classes/Marshaller.php
===================================================================
--- Dev/branches/jos-branch/server/classes/Marshaller.php	(revision 308)
+++ Dev/branches/jos-branch/server/classes/Marshaller.php	(revision 310)
@@ -4,4 +4,7 @@
 
     const OBJ_TYPE = '__objectType';
+    const OBJ_UID = '__objectUid';
+    const REF_TYPE = '__referenceType';
+    const REF_UID = '__referenceUid';
 
     private static function isWrappedObject($obj) {
@@ -9,8 +12,12 @@
     }
 
+    private static function isWrappedReference($obj) {
+        return isset($obj[self::REF_TYPE]);
+    }
+
     public static function marshall($obj) {
         switch (gettype($obj)) {
             case 'array':
-                return array_map(array('Marshaller','marshall'), $obj);
+                return array_map(array('Marshaller', 'marshall'), $obj);
             case 'object':
                 return static::wrapObject($obj);
@@ -24,8 +31,20 @@
         if ($objectType == 'DateTime') {
             return array(self::OBJ_TYPE => 'DateTime', 'timestamp' => $obj->getTimestamp());
+        } else if ($obj instanceof RdfObject) {
+            $array = array(
+                self::OBJ_TYPE => $obj->getType(),
+                self::OBJ_UID => $obj->getUid()
+            );
+            foreach ($obj as $prop => $val) {
+                $array[$prop] = static::marshall($val);
+            }
+            return $array;
+        } else if ($obj instanceof RdfPointer) {
+            return array(
+                self::REF_TYPE => $obj->getType(),
+                self::REF_UID => $obj->getUid()
+            );
         } else {
-            $newObj = static::marshall((array) $obj);
-            $newObj[self::OBJ_TYPE] = get_class($obj);
-            return $newObj;
+            return static::marshall((array) $obj);
         }
     }
@@ -38,6 +57,8 @@
                 if (static::isWrappedObject($obj)) {
                     return static::unwrapObject($obj);
+                } else if (static::isWrappedReference($obj)) {
+                    return static::unwrapReference($obj);
                 } else {
-                    return array_map(array('Marshaller','unmarshall'), $obj);
+                    return array_map(array('Marshaller', 'unmarshall'), $obj);
                 }
             default:
@@ -47,12 +68,22 @@
 
     private static function unwrapObject($obj) {
-        $objectType = $obj[self::OBJ_TYPE];
-        unset($obj[self::OBJ_TYPE]);
+        if (isset($obj[self::OBJ_TYPE])) {
+            $objectType = $obj[self::OBJ_TYPE];
+            unset($obj[self::OBJ_TYPE]);
+        }
+        if (isset($obj[self::OBJ_UID])) {
+            $objectUid = $obj[self::OBJ_UID];
+            unset($obj[self::OBJ_UID]);
+        }
         if ($objectType == 'DateTime') {
             $date = new DateTime();
             $date->setTimestamp($obj['timestamp']);
             return $date;
-        } else if (is_subclass_of($objectType, 'ResearchToolObjectInterface')) {
-            return $objectType::create((object)static::unmarshall($obj));
+        } else if (is_subclass_of($objectType, 'RdfObject')) {
+            $rdfObject = new $objectType($objectUid);
+            foreach ($obj as $prop => $val) {
+                $rdfObject->$prop = static::unmarshall($val);
+            }
+            return $rdfObject;
         } else {
             return $obj;
@@ -60,4 +91,10 @@
     }
 
+    private static function unwrapReference($ref) {
+        $refType = $ref[self::REF_TYPE];
+        $refUid = $ref[self::REF_UID];
+        return new RdfPointer(RdfObject::typeAndUidToResourceUri($refType, $refUid));
+    }
+    
 }
 
Index: Dev/branches/jos-branch/server/classes/Model.php
===================================================================
--- Dev/branches/jos-branch/server/classes/Model.php	(revision 310)
+++ Dev/branches/jos-branch/server/classes/Model.php	(revision 310)
@@ -0,0 +1,584 @@
+<?php
+
+require_once RDFAPI_INCLUDE_DIR . 'RDFAPI.php';
+
+interface RdfResource {
+
+    function getUri();
+
+    function getUid();
+
+    function getType();
+}
+
+abstract class RdfObject implements RdfResource, IteratorAggregate {
+    // namespace and uri functions
+
+    const NS = 'http://tbm.tudelft.nl/researchtool/';
+    const RESOURCES_NS = 'http://tbm.tudelft.nl/researchtool/resources/';
+    const PREDICATES_NS = 'http://tbm.tudelft.nl/researchtool/predicates/';
+
+    public static function isResourceUri($str) {
+        $ptrn = '/^' . preg_quote(self::RESOURCES_NS, '/') . '\w+\/\w+$/';
+        return (bool) preg_match($ptrn, $str);
+    }
+
+    public static function resourceUriToTypeAndUid($uri) {
+        if (!self::isResourceUri($uri)) {
+            throw new Exception("Given URI $uri is not a valid resource.");
+        }
+        $ptrn = '/^' . preg_quote(self::RESOURCES_NS, '/') . '(\w+)\/(\w+)$/';
+        $matches = array();
+        preg_match_all($ptrn, $uri, $matches);
+        return array('type' => $matches[1][0], 'uid' => $matches[2][0]);
+    }
+
+    public static function typeAndUidToResourceUri($type, $uid) {
+        return self::RESOURCES_NS . $type . '/' . $uid;
+    }
+
+    // type functions
+
+    private static $fieldsCache = array();
+
+    private static function TYPE() {
+        return get_called_class();
+    }
+
+    private static function FIELDS() {
+        $type = static::TYPE();
+        if (!isset(self::$fieldsCache[$type])) {
+            self::$fieldsCache[$type] = static::createFIELDS();
+        }
+        return self::$fieldsCache[$type];
+    }
+
+    /** Provides the field of this object - implemented by specific type classes
+     * Retrieves an array with the specification of the fields of this object.
+     * The array contains RdfField objects. This function is called only once
+     * per type, because the result is cached.
+     */
+    protected abstract static function createFIELDS();
+
+    // instance fields
+
+    private $uid = null;
+    private $uri = null;
+    private $values = array();
+
+    public function getUri() {
+        return $this->uri;
+    }
+
+    public function getUid() {
+        return $this->uid;
+    }
+
+    public function getType() {
+        return static::TYPE();
+    }
+
+    // PHP magic functions to expose values
+
+    public function __construct($uid = null, $values = array()) {
+        if (empty($uid)) {
+            $this->uid = md5(uniqid(rand(), true));
+        } else {
+            $this->uid = $uid;
+        }
+        $this->uri = self::typeAndUidToResourceUri(static::TYPE(), $this->uid);
+        foreach ($values as $name => $value) {
+            $this->$name = $value;
+        }
+    }
+
+    private function ensure_field($name) {
+        if (!array_key_exists($name, static::FIELDS())) {
+            throw new Exception("Field " . $name . " not defined on " . self::TYPE());
+        }
+    }
+
+    private function get_field($name) {
+        self::ensure_field($name);
+        $fields = static::FIELDS();
+        return $fields[$name];
+    }
+
+    public function __isset($name) {
+        $this->ensure_field($name);
+        return isset($this->values[$name]);
+    }
+
+    public function __get($name) {
+        $field = self::get_field($name);
+        if (isset($this->values[$name])) {
+            return $this->values[$name];
+        }
+        return $field->get_null();
+    }
+
+    public function __set($name, $value) {
+        self::ensure_field($name);
+        $this->values[$name] = $value;
+    }
+
+    public function __unset($name) {
+        unset($this->values[$name]);
+    }
+
+    public function getIterator() {
+        return new ArrayIterator($this->values);
+    }
+
+    public function __toString() {
+        return self::TYPE() . '(uid=' . $this->uid . ')';
+    }
+
+    // RDF database functions
+
+    private static function get_db_filename() {
+        $fileName = 'data/' . static::TYPE() . 's/' . static::TYPE() . 's.rdf';
+        $dirName = dirname($fileName);
+        if (!is_dir($dirName)) {
+            mkdir($dirName, 0777 /* PHP's default value */, $recursive = TRUE);
+        }
+        return $fileName;
+    }
+
+    private static function get_model() {
+        $fileName = self::get_db_filename();
+        $model = ModelFactory::getDefaultModel();
+        if (file_exists($fileName)) {
+            $model->load($fileName);
+        }
+        $model->addNamespace('rtr', self::RESOURCES_NS);
+        $model->addNamespace('rtp', self::PREDICATES_NS);
+        return $model;
+    }
+
+    private static function save_model($model) {
+        $fileName = self::get_db_filename();
+        return $model->saveAs($fileName, 'rdf');
+    }
+
+    protected function evaluate() {
+        foreach (static::FIELDS() as $name => $field) {
+            if ($field->required()
+                    && (!is_set($this->values[$name])
+                    || ( $field->multiple() && empty($this->values[$name]) ) )) {
+                throw new Exception("Required field $name not found.");
+            }
+        }
+    }
+
+    public function save() {
+        $this->evaluate();
+
+        $model = self::get_model();
+
+        // create new resource and remove old saved resource
+        $resource = new Resource($this->uri);
+        $model->subtract($model->find($resource, null, null));
+
+        // set type
+        $model->add(new Statement($resource,
+                        new Resource(RDF_NAMESPACE_URI . 'type'),
+                        new Resource(self::RESOURCES_NS . static::TYPE())));
+
+        // add fields
+        foreach (static::FIELDS() as $name => $field) {
+            if (isset($this->values[$name])) {
+                $values = $this->values[$name];
+                if (!$field->multiple()) {
+                    $values = array($values);
+                }
+                foreach ($values as $value) {
+                    $type = $field->type();
+                    $type::save($model, $resource, $name, $value);
+                }
+            }
+        }
+
+        if (!self::save_model($model)) {
+            throw new Exception('Save failed: internal RDFAPI error.');
+        }
+    }
+
+    public static function get($predicates = array()) {
+        $model = self::get_model();
+
+        $query = '';
+        $query .= "PREFIX predicates: <" . self::PREDICATES_NS . ">\n";
+        $query .= "PREFIX resources: <" . self::RESOURCES_NS . ">\n";
+        $query .= "SELECT *\n";
+        $query .= "WHERE {\n";
+        $query .= "\t?object a resources:" . static::TYPE() . " .\n";
+        foreach (static::FIELDS() as $name => $field) {
+            if (!$field->multiple()) {
+                $cond = "?object predicates:" . $name . " ?" . $name;
+                if ($field->required() || array_key_exists($name, $predicates)) {
+                    $query .= "\t$cond .\n";
+                } else {
+                    $query .= "\tOPTIONAL { $cond . }\n";
+                }
+            }
+        }
+        if (!empty($predicates)) {
+            $preds = array();
+            foreach ($predicates as $name => $value) {
+                if ($name == 'uid') {
+                    if (!is_string($value)) {
+                        $value = $value->getUid();
+                    }
+                    $preds[] = 'str(?object) = "' . self::RESOURCES_NS . self::TYPE() . '/' . $value . '"';
+                } else {
+                    $type = self::get_field($name)->type();
+                    $preds[] = $type::predicate($name, $value);
+                }
+            }
+            $query .= "\tFILTER ( " . join(" && ", $preds) . " ) .\n";
+        }
+        $query .= "}\n";
+
+        $results = $model->sparqlQuery($query);
+        $objects = array();
+        if (!empty($results)) {
+            $realClass = self::TYPE();
+            foreach ($results as $result) {
+                $uri = $result['?object']->uri;
+                $values = array();
+                foreach (static::FIELDS() as $name => $field) {
+                    if (!$field->multiple()) {
+                        $queryName = "?$name";
+                        if (isset($result[$queryName]) && !empty($result[$queryName])) {
+                            $type = $field->type();
+                            $values[$name] = $type::load($result[$queryName]);
+                        }
+                    } else {
+                        $values[$name] = self::getMultiple($model, $uri, $name, $field);
+                    }
+                }
+                $info = self::resourceUriToTypeAndUid($uri);
+                $objects[] = new $realClass($info['uid'], $values);
+            }
+        }
+        return $objects;
+    }
+
+    private static function getMultiple($model, $uri, $name, $field) {
+        $query = '';
+        $query .= "PREFIX predicates: <" . self::PREDICATES_NS . ">\n";
+        $query .= "SELECT DISTINCT ?item\n";
+        $query .= "WHERE { <$uri> predicates:$name ?item . }\n";
+
+        $results = $model->sparqlQuery($query);
+        $values = array();
+        if (!empty($results)) {
+            foreach ($results as $result) {
+                $type = $field->type();
+                $values[] = $type::load($result['?item']);
+            }
+        }
+        return $values;
+    }
+
+}
+
+class RdfPointer implements RdfResource {
+
+    private $uri = null;
+    private $uid = null;
+    private $type = null;
+
+    public function __construct($uri) {
+        $this->uri = $uri;
+        $info = RdfObject::resourceUriToTypeAndUid($uri);
+        $this->uid = $info['uid'];
+        $this->type = $info['type'];
+    }
+
+    public function getUri() {
+        return $this->uri;
+    }
+
+    public function getUid() {
+        return $this->uid;
+    }
+
+    public function getType() {
+        return $this->type;
+    }
+
+    public function get() {
+        $type = $this->type;
+        return $type::get(array('uid' => $this->uid));
+    }
+
+}
+
+class RdfField {
+
+    const REQUIRED = 1;
+    const MULTIPLE = 2;
+
+    private $type;
+    private $conditions;
+
+    public function __construct($type, $conditions = array()) {
+        $this->type = $type;
+        $this->conditions = $conditions;
+    }
+
+    public function type() {
+        return $this->type;
+    }
+
+    public function required() {
+        return in_array(self::REQUIRED, $this->conditions);
+    }
+
+    public function multiple() {
+        return in_array(self::MULTIPLE, $this->conditions);
+    }
+
+}
+
+function RdfField($type, $conditions = array()) {
+    return new RdfField($type, $conditions);
+}
+
+interface RdfType {
+
+    static function save($model, $resource, $predicateUri, $value);
+
+    static function load($value);
+
+    static function predicate($name, $value);
+}
+
+class RdfString implements RdfType {
+
+    static function save($model, $resource, $name, $value) {
+        $obj = new Literal($value);
+        $model->add(new Statement($resource, new Resource(RdfObject::PREDICATES_NS . $name), $obj));
+    }
+
+    static function load($value) {
+        return $value->label;
+    }
+
+    static function predicate($name, $value) {
+        return 'str(?' . $name . ') = "' . $value . '"';
+    }
+
+}
+
+function RdfString() {
+    return new RdfString();
+}
+
+class RdfDatetime implements RdfType {
+
+    static function save($model, $resource, $name, $value) {
+        $obj = new Literal($value->getTimestamp());
+        $model->add(new Statement($resource, new Resource(RdfObject::PREDICATES_NS . $name), $obj));
+    }
+
+    static function load($value) {
+        $obj = new DateTime();
+        $obj->setTimestamp(intval($value->label));
+        return $obj;
+    }
+
+    static function predicate($name, $value) {
+        return 'str(?' . $name . ') = "' . $value . '"';
+    }
+
+}
+
+function RdfDatetime() {
+    return new RdfDatetime();
+}
+
+class RdfBoolean implements RdfType {
+
+    static function save($model, $resource, $name, $value) {
+        $model->add(new Statement($resource,
+                        new Resource(RdfObject::PREDICATES_NS . $name),
+                        new Literal((bool) $value)));
+    }
+
+    static function load($value) {
+        return (bool) $value->label;
+    }
+
+    static function predicate($name, $value) {
+        return 'str(?' . $name . ') = "' . $value . '"';
+    }
+
+}
+
+function RdfBoolean() {
+    return new RdfBoolean();
+}
+
+class RdfReference implements RdfType {
+
+    static function save($model, $resource, $name, $value) {
+        if (!is_string($value)) {
+            $value = $value->getUri();
+        }
+        $obj = new Resource($value);
+        $model->add(new Statement($resource, new Resource(RdfObject::PREDICATES_NS . $name), $obj));
+    }
+
+    static function load($value) {
+        return new RdfPointer($value->uri);
+    }
+
+    static function predicate($name, $value) {
+        return '?' . $name . ' = <' . $value . '>';
+    }
+
+}
+
+function RdfReference() {
+    return new RdfReference();
+}
+
+class Answer extends RdfObject {
+
+    protected static function createFIELDS() {
+        return array(
+            'question' => RdfField(RdfReference()),
+            'values' => RdfField(RdfString(), array(RdfField::MULTIPLE))
+        );
+    }
+
+}
+
+class AnswerSet extends RdfObject {
+
+    protected static function createFIELDS() {
+        return array(
+            'survey' => RdfField(RdfReference()),
+            'respondent' => RdfField(RdfReference()),
+            'datetime' => RdfField(RdfDatetime()),
+            'answers' => RdfField(RdfReference(), array(RdfField::MULTIPLE))
+        );
+    }
+
+}
+
+class Application extends RdfObject {
+
+    protected static function createFIELDS() {
+        return array(
+            'title' => RdfField(RdfString()),
+            'description' => RdfField(RdfString()),
+            'style' => RdfField(RdfString())
+        );
+    }
+
+}
+
+class ApplicationInstance extends RdfObject {
+
+    protected static function createFIELDS() {
+        return array(
+            'application' => RdfField(RdfReference()),
+            'starttime' => RdfField(RdfDatetime()),
+            'endtime' => RdfField(RdfDatetime()),
+            'open' => RdfField(RdfBoolean())
+        );
+    }
+
+}
+
+class Question extends RdfObject {
+
+    protected static function createFIELDS() {
+        return array(
+            'code' => RdfField(RdfString()),
+            'title' => RdfField(RdfString()),
+            'type' => RdfField(RdfString()),
+            'description' => RdfField(RdfString()),
+            'category' => RdfField(RdfString()),
+            'answers' => RdfField(RdfString(), array(RdfField::MULTIPLE))
+        );
+    }
+
+}
+
+class Session extends RdfObject {
+
+    protected static function createFIELDS() {
+        return array(
+            'title' => RdfField(RdfString()),
+            'creator' => RdfField(RdfReference()),
+            'creationdate' => RdfField(RdfDatetime()),
+            'pipeline' => RdfField(RdfReference(), array(RdfField::MULTIPLE))
+        );
+    }
+
+}
+
+class SessionInstance extends RdfObject {
+
+    protected static function createFIELDS() {
+        return array(
+            'title' => RdfField(RdfString()),
+            'location' => RdfField(RdfString()),
+            'facilitator' => RdfField(RdfReference()),
+            'starttime' => RdfField(RdfDatetime()),
+            'endtime' => RdfField(RdfDatetime()),
+            'notes' => RdfField(RdfString(), array(RdfField::MULTIPLE)),
+            'session' => RdfField(RdfReference()),
+            'surveyinstances' => RdfField(RdfReference(), array(RdfField::MULTIPLE)),
+            'applicationinstances' => RdfField(RdfReference(), array(RdfField::MULTIPLE))
+        );
+    }
+
+}
+
+class Survey extends RdfObject {
+
+    protected static function createFIELDS() {
+        return array(
+            'title' => RdfField(RdfString()),
+            'description' => RdfField(RdfString()),
+            'creator' => RdfField(RdfReference()),
+            'questions' => RdfField(RdfString(), array(RdfField::MULTIPLE))
+        );
+    }
+
+}
+
+class SurveyInstance extends RdfObject {
+
+    protected static function createFIELDS() {
+        return array(
+            'survey' => RdfField(RdfReference()),
+            'starttime' => RdfField(RdfDatetime()),
+            'endtime' => RdfField(RdfDatetime()),
+            'open' => RdfField(RdfBoolean()),
+            'presetanswers' => RdfField(RdfReference(), array(RdfField::MULTIPLE)),
+            'answersets' => RdfField(RdfReference(), array(RdfField::MULTIPLE))
+        );
+    }
+
+}
+
+class User extends RdfObject {
+
+    protected static function createFIELDS() {
+        return array(
+            'email' => RdfField(RdfString()),
+            'passwordHash' => RdfField(RdfString()),
+            'passwordSalt' => RdfField(RdfString())
+        );
+    }
+
+}
+
+?>
Index: Dev/branches/jos-branch/server/classes/master.php
===================================================================
--- Dev/branches/jos-branch/server/classes/master.php	(revision 308)
+++ Dev/branches/jos-branch/server/classes/master.php	(revision 310)
@@ -8,16 +8,8 @@
  * @author fpvanagthoven
  */
-// Determine our absolute document root
-define('DOC_ROOT', realpath(dirname(__FILE__) . '/../'));
 
 function __autoload($class_name) {
 	if (file_exists('classes/' . $class_name . '.php'))
-		require 'classes/' . $class_name . '.php';
-	else if (file_exists('classes/models/' . $class_name . '.php'))
-		require 'classes/models/' . $class_name . '.php';
-	else if (file_exists('classes/widgets/' . $class_name . '.php'))
-		require 'classes/widgets/' . $class_name . '.php';
-	else if (file_exists('classes/styles/' . $class_name . '.php'))
-		require 'classes/styles/' . $class_name . '.php';
+		require_once 'classes/' . $class_name . '.php';
 }
 
Index: Dev/branches/jos-branch/server/rdfapi/syntax/RdfSerializer.php
===================================================================
--- Dev/branches/jos-branch/server/rdfapi/syntax/RdfSerializer.php	(revision 308)
+++ Dev/branches/jos-branch/server/rdfapi/syntax/RdfSerializer.php	(revision 310)
@@ -196,5 +196,8 @@
 		}
 		// check if model is empty
-		if ($model->size() == 0) return "<". $this->rdf_qname_prefix . RDF_RDF ." xmlns:rdf='".RDF_NAMESPACE_URI."' />";
+		if ($model->size() == 0) {
+            $elementStr = "<". $this->rdf_qname_prefix . RDF_RDF ." xmlns:rdf='".RDF_NAMESPACE_URI."' />";
+            return $elementStr;
+        }
 
 		foreach($nsps as $ns => $pre){
