add most of the model and repositories
authorymh <ymh.work@gmail.com>
Tue, 11 Dec 2012 00:01:41 +0100
changeset 46 7e132e2a48ca
parent 45 37c9a17c3284
child 47 267d67791e05
add most of the model and repositories
server/src/main/java/org/iri_research/renkan/coweb/RenkanSessionModerator.java
server/src/main/java/org/iri_research/renkan/coweb/event/AbstractSyncEventManager.java
server/src/main/java/org/iri_research/renkan/coweb/event/ISyncEventManager.java
server/src/main/java/org/iri_research/renkan/coweb/event/NodeSyncEventManager.java
server/src/main/java/org/iri_research/renkan/coweb/event/ProjectSyncEventManager.java
server/src/main/java/org/iri_research/renkan/models/Project.java
server/src/main/java/org/iri_research/renkan/models/ProjectRevision.java
server/src/main/java/org/iri_research/renkan/models/ProjectSync.java
server/src/main/java/org/iri_research/renkan/models/Relation.java
server/src/main/java/org/iri_research/renkan/repositories/NodesRepository.java
server/src/main/java/org/iri_research/renkan/repositories/ProjectRevisionsRepository.java
server/src/main/java/org/iri_research/renkan/repositories/ProjectRevisionsRepositoryCustom.java
server/src/main/java/org/iri_research/renkan/repositories/ProjectRevisionsRepositoryImpl.java
server/src/main/java/org/iri_research/renkan/repositories/ProjectSyncsRepository.java
server/src/main/java/org/iri_research/renkan/repositories/ProjectSyncsRepositoryCustom.java
server/src/main/java/org/iri_research/renkan/repositories/ProjectSyncsRepositoryImpl.java
server/src/main/java/org/iri_research/renkan/repositories/RelationsRepository.java
server/src/main/web-resources/_firebug/LICENSE
server/src/main/web-resources/_firebug/errorIcon.png
server/src/main/web-resources/_firebug/firebug.css
server/src/main/web-resources/_firebug/firebug.js
server/src/main/web-resources/_firebug/firebug.js.uncompressed.js
server/src/main/web-resources/_firebug/infoIcon.png
server/src/main/web-resources/_firebug/tab_lft_norm.png
server/src/main/web-resources/_firebug/tab_lft_over.png
server/src/main/web-resources/_firebug/tab_rgt_norm.png
server/src/main/web-resources/_firebug/tab_rgt_over.png
server/src/main/web-resources/_firebug/warningIcon.png
server/src/main/webapp/js/corenkan.js
server/src/test/java/org/iri_research/renkan/test/repositories/ProjectSyncsRepositoryTest.java
server/src/test/java/org/iri_research/renkan/test/repositories/ProjectsRepositoryTest.java
--- a/server/src/main/java/org/iri_research/renkan/coweb/RenkanSessionModerator.java	Tue Nov 06 13:23:19 2012 +0100
+++ b/server/src/main/java/org/iri_research/renkan/coweb/RenkanSessionModerator.java	Tue Dec 11 00:01:41 2012 +0100
@@ -44,13 +44,13 @@
 			return super.onSync(data);
 		}
 		
+		ApplicationContext context = SpringConfigurer.getInstance().getApplicationContext();
+				
 		//String className = String.format("org.iri_research.renkan.coweb.event.%sSyncEventManager", sync_type.substring(0, 1).toUpperCase()+sync_type.substring(1));
 		String beanName = String.format("%sSyncEventManager", sync_type.toLowerCase());
 		boolean resDispatch = false; 
 		
 		try {
-			
-			ApplicationContext context = SpringConfigurer.getInstance().getApplicationContext();
 			ISyncEventManager eventManager = (ISyncEventManager)context.getBean(beanName);
 			logger.debug("Debugging on Sync : dispatch to " + beanName);
 			resDispatch = eventManager.dispatchEvent(data);
--- a/server/src/main/java/org/iri_research/renkan/coweb/event/AbstractSyncEventManager.java	Tue Nov 06 13:23:19 2012 +0100
+++ b/server/src/main/java/org/iri_research/renkan/coweb/event/AbstractSyncEventManager.java	Tue Dec 11 00:01:41 2012 +0100
@@ -2,6 +2,13 @@
 
 import java.util.Map;
 
+import javax.inject.Inject;
+
+import org.iri_research.renkan.RenkanException;
+import org.iri_research.renkan.models.Project;
+import org.iri_research.renkan.models.ProjectSync;
+import org.iri_research.renkan.repositories.ProjectSyncsRepository;
+import org.iri_research.renkan.repositories.ProjectsRepository;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -10,8 +17,21 @@
 
 	private final Logger logger = LoggerFactory.getLogger(AbstractSyncEventManager.class);
 	
+	@Inject
+	private ProjectsRepository projectsRepository;
+	
+	@Inject
+	private ProjectSyncsRepository projectSyncsRepository;
+	
+	@Override
+	public ProjectsRepository getProjectsRepository() {
+		return this.projectsRepository;
+	}
+		
 	@Override
 	public boolean dispatchEvent(Map<String, Object> data) {
+		
+		this.saveSyncEvent(data);
 
 		String eventType = (String) data.get("type");
 		
@@ -32,6 +52,39 @@
 		return false;
 	}
 
+	private void saveSyncEvent(Map<String, Object> data) {
+		
+		String project_id = null;
+	
+		@SuppressWarnings("unchecked")
+		Map<String, Object> values = (Map<String, Object>) data.get("value");
+		
+		if(values != null) {
+			project_id = (String) values.get("project_id");
+		}
+		
+		if (project_id == null || "".equals(project_id)) {
+			logger.warn("saveSyncEvent : project id is null. Can not save sync event");
+			return;
+		}
+		
+		Project p = this.projectsRepository.findOne(project_id);
+		
+		if (p == null) {
+			logger.warn("saveSyncEvent : project not found. Can not save sync event");
+			return;
+		}
+		
+
+		try {
+			ProjectSync ps = this.projectSyncsRepository.getProjectSync(data.toString(), p);
+			this.projectSyncsRepository.save(ps);
+		} catch (RenkanException e) {
+			logger.warn("saveSyncEvent : Error when getting Projectr syn object",e);
+		}		
+		
+	}
+
 	@Override
 	public abstract boolean update(Map<String, Object> data);
 
--- a/server/src/main/java/org/iri_research/renkan/coweb/event/ISyncEventManager.java	Tue Nov 06 13:23:19 2012 +0100
+++ b/server/src/main/java/org/iri_research/renkan/coweb/event/ISyncEventManager.java	Tue Dec 11 00:01:41 2012 +0100
@@ -2,6 +2,8 @@
 
 import java.util.Map;
 
+import org.iri_research.renkan.repositories.ProjectsRepository;
+
 public interface ISyncEventManager {
 	
 	public boolean dispatchEvent(Map<String, Object> data);
@@ -10,5 +12,7 @@
 	public boolean insert(Map<String, Object> data);
 	public boolean delete(Map<String, Object> data);
 	public boolean nullOperation(Map<String, Object> data);
+	
+	public ProjectsRepository getProjectsRepository();
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/src/main/java/org/iri_research/renkan/coweb/event/NodeSyncEventManager.java	Tue Dec 11 00:01:41 2012 +0100
@@ -0,0 +1,130 @@
+package org.iri_research.renkan.coweb.event;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.coweb.CowebException;
+import org.iri_research.renkan.models.Node;
+import org.iri_research.renkan.models.Project;
+import org.iri_research.renkan.models.ProjectRevision;
+import org.iri_research.renkan.repositories.NodesRepository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBCollection;
+import com.mongodb.DBObject;
+import com.mongodb.WriteResult;
+
+@Named
+public class NodeSyncEventManager extends AbstractSyncEventManager {
+
+	private final Logger logger = LoggerFactory.getLogger(ProjectSyncEventManager.class);
+
+	@Inject
+	private NodesRepository nodesRepository;
+	
+	
+	public NodesRepository getNodesRepository() {
+		return nodesRepository;
+	}
+
+	@Override
+	public boolean update(Map<String, Object> data) {
+
+		this.logger.debug("ProjectSyncEventManager: update project");
+		
+		@SuppressWarnings("unchecked")
+		Map<String, Object> values = (Map<String, Object>) data.get("value");
+		String node_id = (String) values.get("id");
+		
+		this.logger.debug(String.format("update node %s", node_id));
+		
+		DBCollection projectCollection = this.getNodesRepository().getCollection();
+		DBObject node = projectCollection.findOne(node_id);
+		
+		if (null == node) {
+			throw new CowebException("Node update: node not found", String.format("Node %s not found", node_id));
+		}
+		
+		boolean node_changed = false;
+		// update project
+		for (String fieldname : values.keySet()) {
+			if(!"id".equalsIgnoreCase(fieldname) && node.containsField(fieldname))
+			{
+				Object new_value = values.get(fieldname);
+				Object old_value = node.get(fieldname);
+				if((new_value == null && old_value != null) || (new_value != null && !new_value.equals(old_value))) {
+					node.put(fieldname, new_value);
+					node_changed = true;
+				}
+			}
+		}
+		
+		if(node_changed) {
+			node.put("_id", node_id);
+			WriteResult res = this.getNodesRepository().getCollection().update(new BasicDBObject("_id", node_id), node, true, false);
+			
+			if(!res.getLastError().ok()) {
+				throw new CowebException(String.format("Error when writing node %s", node_id), res.getLastError().getErrorMessage()); 
+			}
+		}
+
+		return false;
+	}
+
+	@Override
+	public boolean insert(Map<String, Object> data) {
+	
+		// get project
+		this.logger.debug("ProjectSyncEventManager: update project");
+		
+		@SuppressWarnings("unchecked")
+		Map<String, Object> values = (Map<String, Object>) data.get("value");
+		String project_id = (String) values.get("project_id");
+
+		Project project = this.getProjectsRepository().findOne(project_id); 
+		
+		if (null == project) {
+			throw new CowebException("node insert: project not found", String.format("Project %s not found", project_id));
+		}
+
+		String node_id = (String)values.get("id");
+		
+		Node node = new Node(node_id, (String)values.get("id"), (String)values.get("description"), (String)values.get("uri"), project);
+		
+		Integer position = (Integer)data.get("position");
+		
+		if(position == null || position < 0) {
+			throw new CowebException("node insert: bad insert position", String.format("Bad position %s not found", position==null?"null":position.toString()));
+		}
+		int index = position.intValue();
+		List<Node> nodes = project.getNodes();
+		if(index > nodes.size()) {
+			index = nodes.size();
+		}
+		nodes.add(index,node);
+
+		this.getNodesRepository().save(node);
+		this.getProjectsRepository().save(project);
+		
+		return false;
+	}
+
+	@Override
+	public boolean delete(Map<String, Object> data) {
+		
+		
+		return false;
+	}
+
+	@Override
+	public boolean nullOperation(Map<String, Object> data) {
+		this.logger.debug("nullOperation: NOP");
+		return false;
+	}
+
+}
--- a/server/src/main/java/org/iri_research/renkan/coweb/event/ProjectSyncEventManager.java	Tue Nov 06 13:23:19 2012 +0100
+++ b/server/src/main/java/org/iri_research/renkan/coweb/event/ProjectSyncEventManager.java	Tue Dec 11 00:01:41 2012 +0100
@@ -5,11 +5,9 @@
 
 import java.util.Map;
 
-import javax.inject.Inject;
 import javax.inject.Named;
 
 import org.coweb.CowebException;
-import org.iri_research.renkan.repositories.ProjectsRepository;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -26,12 +24,9 @@
 public class ProjectSyncEventManager extends AbstractSyncEventManager {
 
 	private final Logger logger = LoggerFactory.getLogger(ProjectSyncEventManager.class);
-	
-	@Inject
-	private ProjectsRepository projectsRepository;
-	
+			
 	private DBCollection getCollection() {		
-		return this.projectsRepository.getCollection();
+		return this.getProjectsRepository().getCollection();
 	}
 	
 	/* Update a project
@@ -48,18 +43,12 @@
 		
 		// get project
 		this.logger.debug(String.format("update project %s", project_id));
-		try {
-			this.logger.debug(String.format("rev Counter %d", projectsRepository.getRevCounter(project_id)));
-		}
-		catch(Exception e){
-			this.logger.error("Bad rev counter",e);
-		}
 		
 		DBCollection projectCollection = this.getCollection();
 		DBObject project = projectCollection.findOne(project_id);
 		
 		if (null == project) {
-			throw new CowebException("Project not found", String.format("Project %s not found", project_id));
+			throw new CowebException("Project update: project not found", String.format("Project %s not found", project_id));
 		}
 		
 		boolean project_changed = false;
--- a/server/src/main/java/org/iri_research/renkan/models/Project.java	Tue Nov 06 13:23:19 2012 +0100
+++ b/server/src/main/java/org/iri_research/renkan/models/Project.java	Tue Dec 11 00:01:41 2012 +0100
@@ -1,7 +1,11 @@
 package org.iri_research.renkan.models;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.data.mongodb.core.mapping.DBRef;
 import org.springframework.data.mongodb.core.mapping.Document;
 
 @Document(collection="projects")
@@ -11,6 +15,15 @@
 	private static Logger logger = LoggerFactory.getLogger(Project.class); 
 			
 	private int revCounter = 1;
+		
+	// Nodes
+	@DBRef
+	private List<Node> nodes = new ArrayList<Node>();
+	
+	// Relations
+	@DBRef
+	private List<Relation> relations = new ArrayList<Relation>();
+
 	
 	public Project(String id, String title, String description, String uri,
 			int revCounter) {
@@ -29,5 +42,14 @@
 	public int getRevCounter() {
 		return revCounter;
 	}
+	
+	public List<Node> getNodes() {
+		return nodes;
+	}
+
+	public List<Relation> getRelations() {
+		return relations;
+	}	
+
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/src/main/java/org/iri_research/renkan/models/ProjectRevision.java	Tue Dec 11 00:01:41 2012 +0100
@@ -0,0 +1,68 @@
+package org.iri_research.renkan.models;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.bson.types.ObjectId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.data.mongodb.core.mapping.DBRef;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document(collection="projectRevisions")
+public class ProjectRevision extends AbstractRenkanModel<ObjectId> {
+
+	@SuppressWarnings("unused")	
+	private static Logger logger = LoggerFactory.getLogger(ProjectRevision.class);
+	
+	private int revision;
+	
+	@DBRef
+	private Project project;
+	
+	private Date created;
+	
+	// Nodes
+	private List<Node> nodes = new ArrayList<Node>();
+	
+	// Relations
+	private List<Relation> relations = new ArrayList<Relation>();
+
+
+	@SuppressWarnings("unused")
+	private ProjectRevision() {
+		super();
+	}
+
+	public ProjectRevision(ObjectId id, String title, String description,
+			String uri, Project project, int revision, Date created) {
+		super(id, title, description, uri);
+		this.project = project;
+		this.revision = revision;
+		if(created == null) {
+			this.created = new Date(System.currentTimeMillis());
+		}
+	}
+
+	public int getRevision() {
+		return revision;
+	}
+	
+	public Project getProject() {
+		return project;
+	}
+	
+	public List<Node> getNodes() {
+		return nodes;
+	}
+
+	public List<Relation> getRelations() {
+		return relations;
+	}
+
+	public Date getCreated() {
+		return created;
+	}
+		
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/src/main/java/org/iri_research/renkan/models/ProjectSync.java	Tue Dec 11 00:01:41 2012 +0100
@@ -0,0 +1,53 @@
+package org.iri_research.renkan.models;
+
+import java.util.Date;
+
+import org.bson.types.ObjectId;
+import org.springframework.data.mongodb.core.mapping.DBRef;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+
+@Document(collection="projectSyncs")
+public class ProjectSync {
+
+	private ObjectId id;
+	
+	private String data;
+	
+	@DBRef
+	private Project project;
+	
+	private int revision;
+	
+	private Date created;
+
+	public ProjectSync(ObjectId id, String data, Project project, int revision,
+			Date created) {
+		this.id = id;
+		this.data = data;
+		this.project = project;
+		this.revision = revision;
+		this.created = created;
+		if(this.created == null) {
+			this.created = new Date(System.currentTimeMillis());
+		}
+	}
+
+	public ObjectId getId() {
+		return id;
+	}
+
+	public String getData() {
+		return data;
+	}
+
+	public Project getProject() {
+		return project;
+	}
+
+	public int getRevision() {
+		return revision;
+	}
+	
+	
+}
--- a/server/src/main/java/org/iri_research/renkan/models/Relation.java	Tue Nov 06 13:23:19 2012 +0100
+++ b/server/src/main/java/org/iri_research/renkan/models/Relation.java	Tue Dec 11 00:01:41 2012 +0100
@@ -1,22 +1,27 @@
 package org.iri_research.renkan.models;
 
+import org.bson.types.ObjectId;
 import org.springframework.data.mongodb.core.mapping.DBRef;
 import org.springframework.data.mongodb.core.mapping.Document;
 
 
 @Document(collection="relations")
-public class Relation extends AbstractRenkanModel<String> {
+public class Relation extends AbstractRenkanModel<ObjectId> {
 
 	@DBRef
 	private Node srcNode;
 	
 	@DBRef
 	private Node tgtNode;
+	
+	@DBRef
+	private Project project;
 
-	public Relation(String id, String title, String description, String uri, Node srcNode, Node tgtNode) {
+	public Relation(ObjectId id, String title, String description, String uri, Node srcNode, Node tgtNode, Project project) {
 		super(id,title, description, uri);
 		this.srcNode = srcNode;
-		this.tgtNode = tgtNode;				
+		this.tgtNode = tgtNode;
+		this.project = project;
 	}
 
 }
--- a/server/src/main/java/org/iri_research/renkan/repositories/NodesRepository.java	Tue Nov 06 13:23:19 2012 +0100
+++ b/server/src/main/java/org/iri_research/renkan/repositories/NodesRepository.java	Tue Dec 11 00:01:41 2012 +0100
@@ -1,8 +1,7 @@
 package org.iri_research.renkan.repositories;
 
 import org.iri_research.renkan.models.Node;
-import org.springframework.data.repository.CrudRepository;
 
-public interface NodesRepository extends CrudRepository<Node, String> {
+public interface NodesRepository extends IRenkanRepository<Node, String> {
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/src/main/java/org/iri_research/renkan/repositories/ProjectRevisionsRepository.java	Tue Dec 11 00:01:41 2012 +0100
@@ -0,0 +1,10 @@
+package org.iri_research.renkan.repositories;
+
+import org.bson.types.ObjectId;
+import org.iri_research.renkan.models.ProjectRevision;
+
+public interface ProjectRevisionsRepository extends		
+		IRenkanRepository<ProjectRevision, ObjectId>,
+		ProjectRevisionsRepositoryCustom {
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/src/main/java/org/iri_research/renkan/repositories/ProjectRevisionsRepositoryCustom.java	Tue Dec 11 00:01:41 2012 +0100
@@ -0,0 +1,10 @@
+package org.iri_research.renkan.repositories;
+
+import org.iri_research.renkan.models.Project;
+import org.iri_research.renkan.models.ProjectRevision;
+
+public interface ProjectRevisionsRepositoryCustom {
+	
+	public ProjectRevision getProjectRevision(Project project, int revision);
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/src/main/java/org/iri_research/renkan/repositories/ProjectRevisionsRepositoryImpl.java	Tue Dec 11 00:01:41 2012 +0100
@@ -0,0 +1,28 @@
+package org.iri_research.renkan.repositories;
+
+import java.util.Date;
+
+import org.iri_research.renkan.models.Project;
+import org.iri_research.renkan.models.ProjectRevision;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ProjectRevisionsRepositoryImpl implements
+		ProjectRevisionsRepositoryCustom {
+	
+	@Override
+	public ProjectRevision getProjectRevision(Project project, int revision) {
+		ProjectRevision pr = new ProjectRevision(
+				null,
+				project.getTitle(),
+				project.getDescription(),
+				project.getUri(),
+				project,
+				revision,
+				new Date(System.currentTimeMillis())
+		);
+		
+		return pr;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/src/main/java/org/iri_research/renkan/repositories/ProjectSyncsRepository.java	Tue Dec 11 00:01:41 2012 +0100
@@ -0,0 +1,10 @@
+package org.iri_research.renkan.repositories;
+
+import org.bson.types.ObjectId;
+import org.iri_research.renkan.models.ProjectSync;
+
+public interface ProjectSyncsRepository extends		
+		IRenkanRepository<ProjectSync, ObjectId>,
+		ProjectSyncsRepositoryCustom {
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/src/main/java/org/iri_research/renkan/repositories/ProjectSyncsRepositoryCustom.java	Tue Dec 11 00:01:41 2012 +0100
@@ -0,0 +1,13 @@
+package org.iri_research.renkan.repositories;
+
+import org.iri_research.renkan.RenkanException;
+import org.iri_research.renkan.models.Project;
+import org.iri_research.renkan.models.ProjectSync;
+
+public interface ProjectSyncsRepositoryCustom {
+	
+	public ProjectSync getProjectSync(String data, Project project) throws RenkanException;
+	
+	public ProjectSync getProjectSync(String data, String project_id) throws RenkanException;
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/src/main/java/org/iri_research/renkan/repositories/ProjectSyncsRepositoryImpl.java	Tue Dec 11 00:01:41 2012 +0100
@@ -0,0 +1,54 @@
+package org.iri_research.renkan.repositories;
+
+import java.util.Date;
+
+import org.iri_research.renkan.RenkanException;
+import org.iri_research.renkan.models.Project;
+import org.iri_research.renkan.models.ProjectSync;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ProjectSyncsRepositoryImpl implements
+		ProjectSyncsRepositoryCustom {
+
+	@Autowired
+	private ProjectsRepository projectRepository;
+	
+	@Override
+	public ProjectSync getProjectSync(String data, Project project) throws RenkanException {
+		
+		if(project == null) {
+			throw new RenkanException("ProjectSyncsRepository : Null Project."); 
+		}
+		
+		ProjectSync ps = new ProjectSync(
+				null,
+				data,
+				project,
+				this.projectRepository.getRevCounter(project.getId()),
+				new Date(System.currentTimeMillis())
+		);
+		
+		return ps;
+	}
+
+	@Override
+	public ProjectSync getProjectSync(String data, String project_id)
+			throws RenkanException {
+		
+		if(project_id == null || "".equals(project_id) ) {
+			throw new RenkanException("ProjectSyncsRepository : Null or empty project id.");
+		}
+		
+		Project p = this.projectRepository.findOne(project_id);
+		
+		if(p == null) {
+			throw new RenkanException("ProjectSyncsRepository : project not found for id " + project_id);
+		}
+		
+		return this.getProjectSync(data, p);
+		
+	}
+
+}
--- a/server/src/main/java/org/iri_research/renkan/repositories/RelationsRepository.java	Tue Nov 06 13:23:19 2012 +0100
+++ b/server/src/main/java/org/iri_research/renkan/repositories/RelationsRepository.java	Tue Dec 11 00:01:41 2012 +0100
@@ -1,8 +1,7 @@
 package org.iri_research.renkan.repositories;
 
 import org.iri_research.renkan.models.Relation;
-import org.springframework.data.repository.CrudRepository;
 
-public interface RelationsRepository extends CrudRepository<Relation, String> {
+public interface RelationsRepository extends IRenkanRepository<Relation, String> {
 
 }
--- a/server/src/main/webapp/js/corenkan.js	Tue Nov 06 13:23:19 2012 +0100
+++ b/server/src/main/webapp/js/corenkan.js	Tue Dec 11 00:01:41 2012 +0100
@@ -1,6 +1,6 @@
 define([
     "dojo",
-    "coweb/main",
+    "coweb/main"
 ], function(dojo, coweb) {
 
     var CoRenkanApp = function() {
@@ -48,20 +48,59 @@
 	        		console.log(c);
 	        		values = {
 	        		    id: obj.id,
-	        		    type: "project"
+	        		    type: "project",
+	        		    project_id: obj.id
 	        		};
 	        		values[field] = c;
 	        		that.collab.sendSync("project", values);
 	        	});
     		})(fieldIndex);
     	}
+    	project.get("nodes").bind("add", function(obj, c, options) {
+    		console.log("add nodes",obj, c, options);
+    		values = obj.toJSON();
+    		new_values = {
+    			id: obj.id,
+    			type: "node",
+    			index: options.index,
+    			project_id : obj.get("project").id
+    		};
+    		for(var k in new_values) {
+    			values[k] = new_values[k];
+    		}
+    		that.collab.sendSync("node", values, "insert", options.index);
+    	});
+    	project.get("nodes").bind("remove", function(obj, c, options) {
+    		console.log("delete nodes",obj, c, options);
+    		values = {
+        	    id: obj.id,
+        	    type: "node",
+        	    index: options.index,
+        	    project_id : obj.get("project").id
+        	};
+    		that.collab.sendSync("node", values, "delete", options.index);
+    	});
+    	project.get("nodes").bind("change", function(obj, c) {
+    		console.log("change nodes",obj, c);
+    		values = {
+    		    id: obj.id,
+        	    type: "node",
+        	    project_id : obj.get("project").id
+        	};
+    		for(var f in c) {
+    			if(c[f]) {
+    				values[f] = obj.get(f);
+    			}
+    		}
+        	that.collab.sendSync("node", values);
+    	});
     	this.project = project;
     	this.initCollab(project.id);
     };
     
     
     /**
-     * Called when a remote data store changes in some manner. Dispatches to
+     * Called when a remote data store for project changes in some manner. Dispatches to
      * local methods for insert, update, delete handling.
      * TODO: manage project list change on server
      * @param args Cooperative web event
@@ -80,6 +119,25 @@
         }*/
     };
     
+
+    /**
+     * Called when a remote data store for nodes changes in some manner. Dispatches to
+     * local methods for insert, update, delete handling.
+     * @param args Cooperative web event
+     */
+    proto.onRemoteNodeChange = function(args) {    	
+    	console.log(args);
+        if (args.type === "insert") {
+            this.onRemoteNodeInsert(value, args.position);
+        } else if (args.type === "update") {
+            this.onRemoteNodeUpdate(value, args.position);
+        } else if (args.type === "delete") {
+            this.onRemoteNodeDelete(args.position);
+        }
+    };
+
+    
+    
     /**
      * Called when a project attribute changes value in a remote data store.
      * Updates the attribute value of the item with the same id in the local
@@ -103,6 +161,81 @@
     	}
     	
     };
+    
+
+    
+    /**
+     * Called when a node attribute changes value in a remote data store.
+     * Updates the attribute value of the item with the same id in the local
+     * data store.
+     *
+     * @param value Item data sent by remote data store
+     * @param position Which item to update.
+     */
+    proto.onRemoteNodeInsert = function(values, position) {
+    	var project_id = values['project_id'];
+    	if(typeof(project_id) === "undefined") {
+    		return;
+		}
+    	
+    	if(this.project != null && project_id == this.project.id) {
+    		for(var fieldname in values) {
+    			if(fieldname != "id" && fieldname != "type") {
+    				this.project.set(fieldname, values[fieldname]);
+    			}
+    		}
+    	}
+    	
+    };
+    
+    /**
+     * Called when a node attribute changes value in a remote data store.
+     * Updates the attribute value of the item with the same id in the local
+     * data store.
+     *
+     * @param value Item data sent by remote data store
+     * @param position Which item to update.
+     */
+    proto.onRemoteNodeUpdate = function(values, position) {
+    	var project_id = values['project_id'];
+    	if(typeof(project_id) === "undefined") {
+    		return;
+		}
+    	
+    	if(this.project != null && project_id == this.project.id) {
+    		for(var fieldname in values) {
+    			if(fieldname != "id" && fieldname != "type") {
+    				this.project.set(fieldname, values[fieldname]);
+    			}
+    		}
+    	}
+    	
+    };
+    
+    
+    /**
+     * Called when a node attribute changes value in a remote data store.
+     * Updates the attribute value of the item with the same id in the local
+     * data store.
+     *
+     * @param value Item data sent by remote data store
+     * @param position Which item to update.
+     */
+    proto.onRemoteNodeDelete = function(position) {
+    	var project_id = values['id'];
+    	if(typeof(project_id) === "undefined") {
+    		return;
+		}
+    	
+    	if(this.project != null && project_id == this.project.id) {
+    		for(var fieldname in values) {
+    			if(fieldname != "id" && fieldname != "type") {
+    				this.project.set(fieldname, values[fieldname]);
+    			}
+    		}
+    	}
+    	
+    };
         
     var app = new CoRenkanApp();
     dojo.ready(function() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/src/test/java/org/iri_research/renkan/test/repositories/ProjectSyncsRepositoryTest.java	Tue Dec 11 00:01:41 2012 +0100
@@ -0,0 +1,156 @@
+package org.iri_research.renkan.test.repositories;
+
+
+import java.util.ArrayList;
+
+import org.iri_research.renkan.RenkanException;
+import org.iri_research.renkan.models.Project;
+import org.iri_research.renkan.models.ProjectSync;
+import org.iri_research.renkan.repositories.ProjectSyncsRepository;
+import org.iri_research.renkan.repositories.ProjectsRepository;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration("repositories-context.xml")
+public class ProjectSyncsRepositoryTest {
+
+	private Logger logger = LoggerFactory.getLogger(ProjectSyncsRepositoryTest.class);
+	
+	@Autowired
+	private ProjectsRepository projectRepository;
+
+	@Autowired
+	private ProjectSyncsRepository projectSyncsRepository;
+	
+	
+	private ArrayList<Project> testProjects = new ArrayList<Project>();
+	
+	public ProjectSyncsRepositoryTest() {
+	}
+	
+	@Before
+	public void setup() {
+		
+		logger.debug("Setup");		
+		ArrayList<Project> pl = new ArrayList<Project>();
+		pl.add(new Project(null, "test1", "desc1", "http://localhost:8080/rest/projects/id1"));
+		pl.add(new Project(null, "test2", "desc2", "http://localhost:8080/rest/projects/id2"));
+		logger.debug("Setup : new Project ");
+		for(Project p: projectRepository.save(pl)) {
+			this.testProjects.add(p);
+		}
+	}
+	
+	@After
+	public void teardown() {
+		logger.debug("Teardown");
+		projectRepository.deleteAll();
+		projectSyncsRepository.deleteAll();
+	}
+	
+
+	@Test
+	public void testGetCollection() {
+		String collectionName = this.projectSyncsRepository.getCollection().getName();
+		
+		Assert.assertEquals("The collection name should be projectSyncs", "projectSyncs", collectionName);
+		
+	}
+	
+	@Test
+	public void testGetProjectSync() throws RenkanException {
+		
+		Project p = projectRepository.findOne(this.testProjects.get(0).getId());
+		
+		String data = "{\"example\":\"this is an example\"}";
+		
+		ProjectSync ps = projectSyncsRepository.getProjectSync(data, p);
+		
+		ps = this.projectSyncsRepository.save(ps);
+				
+		
+		ps = this.projectSyncsRepository.findOne(ps.getId());
+		
+		Assert.assertNotNull(ps);
+		Assert.assertEquals(data, ps.getData());
+				
+	}
+	
+	
+	@Test
+	public void testGetProjectSyncRevision() throws RenkanException {
+		
+		Project p = projectRepository.findOne(this.testProjects.get(0).getId());
+		
+		String data = "{\"example\":\"this is an example\"}";
+		
+		ProjectSync ps = projectSyncsRepository.getProjectSync(data, p);
+		
+		ps = this.projectSyncsRepository.save(ps);
+		ps = this.projectSyncsRepository.findOne(ps.getId());
+				
+		p = projectRepository.findOne(this.testProjects.get(0).getId());
+		
+		Assert.assertNotNull(ps.getProject());
+		Assert.assertEquals(p.getId(), ps.getProject().getId());
+		Assert.assertEquals("Revision of the project sync mustbe one less tha the rev counter pf the project", p.getRevCounter()-1, ps.getRevision());
+		
+		Assert.assertEquals("Revision of the project sync mustbe one less tha the rev counter of its project", ps.getProject().getRevCounter()-1, ps.getRevision());
+		
+	}
+	
+	@Test(expected=RenkanException.class)
+	public void testGetProjectSyncExceptionNullProject() throws RenkanException {
+		
+		String data = "{\"example\":\"this is an example\"}";
+		Project p = null;
+		ProjectSync ps = projectSyncsRepository.getProjectSync(data, p);
+		
+		// shold never be executed.
+		Assert.assertNull(ps);
+	}
+	
+	@Test(expected=RenkanException.class)
+	public void testGetProjectSyncExceptionNullId() throws RenkanException {
+		
+		String data = "{\"example\":\"this is an example\"}";
+		String project_id = null;
+		ProjectSync ps = projectSyncsRepository.getProjectSync(data, project_id);
+		
+		// shold never be executed.
+		Assert.assertNull(ps);
+	}
+	
+	@Test(expected=RenkanException.class)
+	public void testGetProjectSyncExceptionEmptyId() throws RenkanException {
+		
+		String data = "{\"example\":\"this is an example\"}";
+		String project_id = "";
+		ProjectSync ps = projectSyncsRepository.getProjectSync(data, project_id);
+		
+		// shold never be executed.
+		Assert.assertNull(ps);
+	}
+	
+	@Test(expected=RenkanException.class)
+	public void testGetProjectSyncExceptionBadId() throws RenkanException {
+		
+		String data = "{\"example\":\"this is an example\"}";
+		String project_id = "BAD_ID";
+		ProjectSync ps = projectSyncsRepository.getProjectSync(data, project_id);
+		
+		// shold never be executed.
+		Assert.assertNull(ps);
+	}
+	
+}
--- a/server/src/test/java/org/iri_research/renkan/test/repositories/ProjectsRepositoryTest.java	Tue Nov 06 13:23:19 2012 +0100
+++ b/server/src/test/java/org/iri_research/renkan/test/repositories/ProjectsRepositoryTest.java	Tue Dec 11 00:01:41 2012 +0100
@@ -1,7 +1,6 @@
 package org.iri_research.renkan.test.repositories;
 
 
-import java.sql.Array;
 import java.util.ArrayList;
 
 import org.iri_research.renkan.models.Project;