Skip to content

Commit

Permalink
Topicmaps: update and extend API (#269).
Browse files Browse the repository at this point in the history
Overall the refId is stripped from the Topicmaps API.
In preparation to "Interactive read-only maps" (#269).

New methods:
    - void moveTopic(long topicmapId, long topicId, int x, int y)
    - void setTopicVisibility(long topicmapId, long topicId, boolean visibility)
Changed methods:
    - addTopicToTopicmap() returns void and is invoked via POST
    - addAssociationToTopicmap() returns void and is invoked via POST
    - removeAssociationFromTopicmap() has no refId parameter

The 2 provider classes are dropped:
    - TopicmapProvider
    - RefIdProvider

Furthermore a core fix: DMObject's setCompositeValue() opens a transaction.

CAUTION: the "accesscontrol" branch is currently not fully functional.

See ticket 269
  • Loading branch information
jri committed Jul 25, 2012
1 parent d98e2ba commit 237f2a6
Show file tree
Hide file tree
Showing 13 changed files with 145 additions and 226 deletions.
Expand Up @@ -63,6 +63,8 @@ public class AccessControlPlugin extends PluginActivator implements AccessContro
PluginServiceArrivedListener,
PluginServiceGoneListener {

// ------------------------------------------------------------------------------------------------------- Constants

private static final String DEFAULT_USERNAME = "admin";
private static final String DEFAULT_PASSWORD = "";
private static final String ENCRYPTED_PASSWORD_PREFIX = "-SHA256-"; // don't change this
Expand Down
12 changes: 12 additions & 0 deletions modules/dm4-core/src/main/java/de/deepamehta/core/Topic.java
Expand Up @@ -26,9 +26,21 @@ public interface Topic extends DeepaMehtaObject {

// ### TODO: move this methods to DeepaMehtaObject.

/**
* @param assocTypeUri may be null
* @param myRoleTypeUri may be null
* @param othersRoleTypeUri may be null
* @param othersAssocTypeUri may be null
*/
RelatedAssociation getRelatedAssociation(String assocTypeUri, String myRoleTypeUri, String othersRoleTypeUri,
String othersAssocTypeUri, boolean fetchComposite, boolean fetchRelatingComposite);

/**
* @param assocTypeUri may be null
* @param myRoleTypeUri may be null
* @param othersRoleTypeUri may be null
* @param othersAssocTypeUri may be null
*/
Set<RelatedAssociation> getRelatedAssociations(String assocTypeUri, String myRoleTypeUri, String othersRoleTypeUri,
String othersAssocTypeUri, boolean fetchComposite, boolean fetchRelatingComposite);
}
Expand Up @@ -3,6 +3,7 @@
import de.deepamehta.core.Association;
import de.deepamehta.core.AssociationDefinition;
import de.deepamehta.core.DeepaMehtaObject;
import de.deepamehta.core.DeepaMehtaTransaction;
import de.deepamehta.core.RelatedTopic;
import de.deepamehta.core.ResultSet;
import de.deepamehta.core.Topic;
Expand Down Expand Up @@ -179,8 +180,17 @@ public CompositeValue getCompositeValue() {

@Override
public void setCompositeValue(CompositeValue comp, ClientState clientState, Directives directives) {
updateCompositeValue(comp, clientState, directives);
refreshLabel();
DeepaMehtaTransaction tx = dms.beginTx(); // ### FIXME: all other writing API methods need transaction
try {
updateCompositeValue(comp, clientState, directives);
refreshLabel();
tx.success();
} catch (Exception e) {
logger.warning("ROLLBACK!");
throw new RuntimeException("Setting composite value failed (" + comp + ")", e);
} finally {
tx.finish();
}
}

// ---
Expand Down
Expand Up @@ -11,6 +11,7 @@
import de.deepamehta.core.model.TopicRoleModel;
import de.deepamehta.core.osgi.PluginActivator;
import de.deepamehta.core.service.ClientState;
import de.deepamehta.core.service.Directives;

import javax.ws.rs.GET;
import javax.ws.rs.PUT;
Expand All @@ -36,6 +37,15 @@
@Produces("application/json")
public class TopicmapsPlugin extends PluginActivator implements TopicmapsService {

// ------------------------------------------------------------------------------------------------------- Constants

// association type semantics ### TODO: to be dropped. Model-driven manipulators required.
private static final String TOPIC_MAPCONTEXT = "dm4.topicmaps.topic_mapcontext";
private static final String ASSOCIATION_MAPCONTEXT = "dm4.topicmaps.association_mapcontext";
private static final String ROLE_TYPE_TOPICMAP = "dm4.core.default";
private static final String ROLE_TYPE_TOPIC = "dm4.topicmaps.topicmap_topic";
private static final String ROLE_TYPE_ASSOCIATION = "dm4.topicmaps.topicmap_association";

// ---------------------------------------------------------------------------------------------- Instance Variables

private Logger logger = Logger.getLogger(getClass().getName());
Expand All @@ -57,42 +67,64 @@ public Topicmap getTopicmap(@PathParam("id") long topicmapId, @HeaderParam("Cook
return new Topicmap(topicmapId, dms, clientState);
}

@PUT
// ---

@POST
@Path("/{id}/topic/{topic_id}/{x}/{y}")
@Override
public long addTopicToTopicmap(@PathParam("id") long topicmapId, @PathParam("topic_id") long topicId,
public void addTopicToTopicmap(@PathParam("id") long topicmapId, @PathParam("topic_id") long topicId,
@PathParam("x") int x, @PathParam("y") int y) {
AssociationModel model = new AssociationModel("dm4.topicmaps.topic_mapcontext",
new TopicRoleModel(topicmapId, "dm4.core.default"),
new TopicRoleModel(topicId, "dm4.topicmaps.topicmap_topic"),
dms.createAssociation(new AssociationModel(TOPIC_MAPCONTEXT,
new TopicRoleModel(topicmapId, ROLE_TYPE_TOPICMAP),
new TopicRoleModel(topicId, ROLE_TYPE_TOPIC),
new CompositeValue().put("dm4.topicmaps.x", x)
.put("dm4.topicmaps.y", y)
.put("dm4.topicmaps.visibility", true)
);
Association refAssoc = dms.createAssociation(model, null); // FIXME: clientState=null
return refAssoc.getId();
), null); // FIXME: clientState=null
}

@PUT
@POST
@Path("/{id}/association/{assoc_id}")
@Override
public long addAssociationToTopicmap(@PathParam("id") long topicmapId, @PathParam("assoc_id") long assocId) {
AssociationModel model = new AssociationModel("dm4.topicmaps.association_mapcontext",
new TopicRoleModel(topicmapId, "dm4.core.default"),
new AssociationRoleModel(assocId, "dm4.topicmaps.topicmap_association"));
Association refAssoc = dms.createAssociation(model, null); // FIXME: clientState=null
return refAssoc.getId();
public void addAssociationToTopicmap(@PathParam("id") long topicmapId, @PathParam("assoc_id") long assocId) {
dms.createAssociation(new AssociationModel(ASSOCIATION_MAPCONTEXT,
new TopicRoleModel(topicmapId, ROLE_TYPE_TOPICMAP),
new AssociationRoleModel(assocId, ROLE_TYPE_ASSOCIATION)
), null); // FIXME: clientState=null
}

// ---

@PUT
@Path("/{id}/topic/{topic_id}/{x}/{y}")
@Override
public void moveTopic(@PathParam("id") long topicmapId, @PathParam("topic_id") long topicId, @PathParam("x") int x,
@PathParam("y") int y) {
getTopicRefAssociation(topicmapId, topicId).setCompositeValue(new CompositeValue()
.put("dm4.topicmaps.x", x)
.put("dm4.topicmaps.y", y), null, new Directives()); // clientState=null
}

@PUT
@Path("/{id}/topic/{topic_id}/{visibility}")
@Override
public void setTopicVisibility(@PathParam("id") long topicmapId, @PathParam("topic_id") long topicId,
@PathParam("visibility") boolean visibility) {
getTopicRefAssociation(topicmapId, topicId).setCompositeValue(new CompositeValue()
.put("dm4.topicmaps.visibility", visibility), null, new Directives()); // clientState=null
}

// ---

@DELETE
@Path("/{id}/association/{assoc_id}/{ref_id}")
@Path("/{id}/association/{assoc_id}")
@Override
public void removeAssociationFromTopicmap(@PathParam("id") long topicmapId,
@PathParam("assoc_id") long assocId,
@PathParam("ref_id") long refId) {
removeAssociationFromTopicmap(refId);
public void removeAssociationFromTopicmap(@PathParam("id") long topicmapId, @PathParam("assoc_id") long assocId) {
getAssociationRefAssociation(topicmapId, assocId).delete(null); // directives=null
}

// ---

@PUT
@Path("/{id}/translation/{x}/{y}")
@Override
Expand Down Expand Up @@ -131,11 +163,15 @@ public InputStream getTopicmapAndTopicInWebclient() {

// ------------------------------------------------------------------------------------------------- Private Methods

/**
* @param refId ID of the "Association Mapcontext" association that relates to the association to remove.
*/
private void removeAssociationFromTopicmap(long refId) {
dms.deleteAssociation(refId, null); // clientState=null
private Association getTopicRefAssociation(long topicmapId, long topicId) {
return dms.getAssociation(TOPIC_MAPCONTEXT, topicmapId, topicId,
ROLE_TYPE_TOPICMAP, ROLE_TYPE_TOPIC, false, null); // fetchComposite=false, clientState=null
}

private Association getAssociationRefAssociation(long topicmapId, long assocId) {
// ### FIXME: doesn't work! getAssociation() expects 2 topicIDs!
return dms.getAssociation(ASSOCIATION_MAPCONTEXT, topicmapId, assocId,
ROLE_TYPE_TOPICMAP, ROLE_TYPE_ASSOCIATION, false, null); // fetchComposite=false, clientState=null
}

// ---
Expand Down
@@ -1,24 +1,21 @@
package de.deepamehta.plugins.topicmaps.model;

import de.deepamehta.core.Association;
import de.deepamehta.core.JSONEnabled;
import de.deepamehta.core.RelatedAssociation;
import de.deepamehta.core.RelatedTopic;
import de.deepamehta.core.ResultSet;
import de.deepamehta.core.Topic;
import de.deepamehta.core.model.CompositeValue;
import de.deepamehta.core.service.ClientState;
import de.deepamehta.core.service.DeepaMehtaService;
import de.deepamehta.core.util.JSONHelper;

import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONObject;

import java.awt.Point;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
Expand All @@ -32,7 +29,7 @@
* - load from DB (by constructor).
* - Serialization to JSON.
*/
public class Topicmap {
public class Topicmap implements JSONEnabled {

// ---------------------------------------------------------------------------------------------- Instance Variables

Expand Down Expand Up @@ -76,6 +73,7 @@ public boolean containsAssociation(long assocId) {

// ---

@Override
public JSONObject toJSON() {
try {
JSONObject topicmap = new JSONObject();
Expand Down Expand Up @@ -162,17 +160,16 @@ private void loadTopics(ClientState clientState) {
"dm4.core.default", "dm4.topicmaps.topicmap_topic", null, false, true, 0, clientState);
// othersTopicTypeUri=null, fetchComposite=false, fetchRelatingComposite=true, maxResultSize=0
for (RelatedTopic mapTopic : mapTopics) {
Association refAssoc = mapTopic.getAssociation();
addTopic(new TopicmapTopic(mapTopic.getModel(), refAssoc.getCompositeValue(), refAssoc.getId()));
CompositeValue visualizationProperties = mapTopic.getAssociation().getCompositeValue();
addTopic(new TopicmapTopic(mapTopic.getModel(), visualizationProperties));
}
}

private void loadAssociations() {
Set<RelatedAssociation> mapAssocs = topicmapTopic.getRelatedAssociations("dm4.topicmaps.association_mapcontext",
"dm4.core.default", "dm4.topicmaps.topicmap_association", null, false, false);
for (RelatedAssociation mapAssoc : mapAssocs) {
Association refAssoc = mapAssoc.getRelatingAssociation();
addAssociation(new TopicmapAssociation(mapAssoc.getModel(), refAssoc.getId()));
addAssociation(new TopicmapAssociation(mapAssoc.getModel()));
}
}

Expand Down
Expand Up @@ -12,27 +12,9 @@
*/
public class TopicmapAssociation extends AssociationModel {

// ---------------------------------------------------------------------------------------------- Instance Variables

private long refId;

// ---------------------------------------------------------------------------------------------------- Constructors

TopicmapAssociation(AssociationModel assoc, long refId) {
TopicmapAssociation(AssociationModel assoc) {
super(assoc);
this.refId = refId;
}

// -------------------------------------------------------------------------------------------------- Public Methods

@Override
public JSONObject toJSON() {
try {
JSONObject o = super.toJSON();
o.put("ref_id", refId);
return o;
} catch (Exception e) {
throw new RuntimeException("Serialization failed (" + this + ")", e);
}
}
}
Expand Up @@ -13,22 +13,18 @@
/**
* A topic as contained in a topicmap.
* That is a generic topic enriched by visualization properties ("x", "y", "visibility").
* <p>
* Note: the topic's own properties are not initialized.
*/
public class TopicmapTopic extends TopicModel {

// ---------------------------------------------------------------------------------------------- Instance Variables

private CompositeValue visualizationProperties;
private long refId;

// ---------------------------------------------------------------------------------------------------- Constructors

TopicmapTopic(TopicModel topic, CompositeValue visualizationProperties, long refId) {
TopicmapTopic(TopicModel topic, CompositeValue visualizationProperties) {
super(topic);
this.visualizationProperties = visualizationProperties;
this.refId = refId;
}

// -------------------------------------------------------------------------------------------------- Public Methods
Expand All @@ -38,7 +34,6 @@ public JSONObject toJSON() {
try {
JSONObject o = super.toJSON();
o.put("visualization", visualizationProperties.toJSON());
o.put("ref_id", refId);
return o;
} catch (Exception e) {
throw new RuntimeException("Serialization failed (" + this + ")", e);
Expand All @@ -49,14 +44,14 @@ public JSONObject toJSON() {

public int getX() {
// Note: coordinates can have both formats: double (through JavaScript) and integer (programmatically placed).
// TODO: store coordinates always as integers
// ### TODO: store coordinates always as integers
Object x = visualizationProperties.get("x");
return x instanceof Double ? ((Double) x).intValue() : (Integer) x;
}

public int getY() {
// Note: coordinates can have both formats: double (through JavaScript) and integer (programmatically placed).
// TODO: store coordinates always as integers
// ### TODO: store coordinates always as integers
Object y = visualizationProperties.get("y");
return y instanceof Double ? ((Double) y).intValue() : (Integer) y;
}
Expand Down

This file was deleted.

0 comments on commit 237f2a6

Please sign in to comment.