Permalink
Browse files

Topicmaps fix: default map has ACL entries (#298).

Creation of the default topicmap is defered to ensure it gets ACL entries and creator information.

The "accesscontrol" branch should launch properly also if no DB exists.

See ticket 298.
  • Loading branch information...
1 parent a788ec3 commit 2d202ca690116942acb515e671828905d9d04af1 @jri committed Sep 3, 2012
@@ -482,6 +482,8 @@ public void preSendTopicType(TopicType topicType, ClientState clientState) {
hasPermission(username, Operation.CREATE, topicType));
}
+ // ---
+
@Override
public void postInstallPlugin() {
Topic userAccount = createUserAccount(new Credentials(DEFAULT_USERNAME, DEFAULT_PASSWORD));
@@ -550,7 +552,7 @@ private void assignCreator(DeepaMehtaObject object, long usernameId) {
* Fetches the "Username" topic for the "admin" user.
* If the "admin" user doesn't exist an exception is thrown.
*
- * @return The retrieved Username (a Topic of type "Username" / <code>dm4.accesscontrol.username</code>).
+ * @return The fetched Username (a Topic of type "Username" / <code>dm4.accesscontrol.username</code>).
*/
private Topic fetchAdminUser() {
Topic username = fetchUsername(DEFAULT_USERNAME);
@@ -563,7 +565,7 @@ private Topic fetchAdminUser() {
/**
* Fetches the "Username" topic for the specified username.
*
- * @return The retrieved Username (a Topic of type "Username" / <code>dm4.accesscontrol.username</code>),
+ * @return The fetched Username (a Topic of type "Username" / <code>dm4.accesscontrol.username</code>),
* or <code>null</code> if no such Username topic exists.
*/
private Topic fetchUsername(String username) {
@@ -612,7 +614,7 @@ private boolean hasPermission(Topic username, Operation operation, DeepaMehtaObj
// ---
/**
- * Retrieves all ACL entries of the specified object.
+ * Fetches all ACL entries of the specified object.
*/
private Set<RelatedTopic> fetchACLEntries(DeepaMehtaObject object) {
return facetsService.getFacets(object, "dm4.accesscontrol.acl_facet");
@@ -704,7 +706,7 @@ private boolean userIsMember(Topic username, DeepaMehtaObject object) {
* @param username a Topic of type "Username" (<code>dm4.accesscontrol.username</code>).
*/
private boolean userIsOwner(Topic username, DeepaMehtaObject object) {
- Topic owner = getOwner(object);
+ Topic owner = fetchOwner(object);
logger.fine("The owner is " + userInfo(owner));
return owner != null && owner.getId() == username.getId();
}
@@ -718,19 +720,20 @@ private boolean userIsOwner(Topic username, DeepaMehtaObject object) {
* @param username a Topic of type "Username" (<code>dm4.accesscontrol.username</code>).
*/
private boolean userIsCreator(Topic username, DeepaMehtaObject object) {
- Topic creator = getCreator(object);
+ Topic creator = fetchCreator(object);
logger.fine("The creator is " + userInfo(creator));
return creator != null && creator.getId() == username.getId();
}
// ---
/**
- * Retrieves the creator of an object, or <code>null</code> if no creator is set.
+ * Fetches the creator of an object.
*
- * @return a Topic of type "Username" (<code>dm4.accesscontrol.username</code>).
+ * @return a Topic of type "Username" (<code>dm4.accesscontrol.username</code>),
+ * or <code>null</code> if no creator is set.
*/
- private Topic getCreator(DeepaMehtaObject object) {
+ private Topic fetchCreator(DeepaMehtaObject object) {
Topic creator = facetsService.getFacet(object, "dm4.accesscontrol.creator_facet");
if (creator == null) {
return null;
@@ -740,11 +743,12 @@ private Topic getCreator(DeepaMehtaObject object) {
}
/**
- * Retrieves the owner of an object, or <code>null</code> if no owner is set.
+ * Fetches the owner of an object.
*
- * @return a Topic of type "Username" (<code>dm4.accesscontrol.username</code>).
+ * @return a Topic of type "Username" (<code>dm4.accesscontrol.username</code>),
+ * or <code>null</code> if no owner is set.
*/
- private Topic getOwner(DeepaMehtaObject object) {
+ private Topic fetchOwner(DeepaMehtaObject object) {
Topic owner = facetsService.getFacet(object, "dm4.accesscontrol.owner_facet");
if (owner == null) {
return null;
@@ -28,7 +28,7 @@
*
* Hashed by plugin bundle's symbolic name, e.g. "de.deepamehta.topicmaps".
*/
- static private Map<String, PluginImpl> activatedPlugins = new HashMap();
+ private Map<String, PluginImpl> activatedPlugins = new HashMap();
/**
* Context of the DeepaMehta 4 Core bundle.
@@ -56,7 +56,7 @@
* - install the plugin in the database (includes migrations, post-install event, type introduction)
* - initialize the plugin
* - register the plugin's listeners
- * - put the plugin in the pool of activated plugins
+ * - add the plugin to the pool of activated plugins
*
* If this plugin is already activated, nothing is performed and false is returned.
* Otherwise true is returned.
@@ -40,24 +40,24 @@
Topic getTopic(long id, boolean fetchComposite, ClientState clientState);
/**
- * Looks up a single topic by exact property value.
+ * Looks up a single topic by exact value.
* If no such topic exists <code>null</code> is returned.
* If more than one topic is found a runtime exception is thrown.
* <p>
- * IMPORTANT: Looking up a topic this way requires the property to be indexed with indexing mode <code>KEY</code>.
- * This is achieved by declaring the respective data field with <code>indexing_mode: "KEY"</code>
- * (for statically declared data field, typically in <code>types.json</code>) or
- * by calling DataField's {@link DataField#setIndexingMode} method with <code>"KEY"</code> as argument
- * (for dynamically created data fields, typically in migration classes).
+ * IMPORTANT: Looking up a topic this way requires the corresponding type to be indexed with indexing mode
+ * <code>dm4.core.key</code>.
*/
Topic getTopic(String key, SimpleValue value, boolean fetchComposite, ClientState clientState);
ResultSet<Topic> getTopics(String typeUri, boolean fetchComposite, int maxResultSize, ClientState clientState);
/**
* Performs a fulltext search.
+ * <p>
+ * IMPORTANT: Searching topics this way requires the corresponding type to be indexed with indexing mode
+ * <code>dm4.core.fulltext</code> or <code>dm4.core.fulltext_key</code>.
*
- * @param fieldUri The URI of the data field to search. If null is provided all fields are searched.
+ * @param fieldUri The URI of the data field to search. If null is provided all fields are searched. ### FIXDOC
* @param wholeWord If true the searchTerm is regarded as whole word.
* If false the searchTerm is regarded as begin-of-word substring.
*/
@@ -13,7 +13,8 @@
import de.deepamehta.core.osgi.PluginActivator;
import de.deepamehta.core.service.ClientState;
import de.deepamehta.core.service.Directives;
-import de.deepamehta.core.service.listener.PostInstallPluginListener;
+import de.deepamehta.core.service.listener.AllPluginsActiveListener;
+import de.deepamehta.core.service.listener.InitializePluginListener;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
@@ -37,7 +38,8 @@
@Path("/topicmap")
@Consumes("application/json")
@Produces("application/json")
-public class TopicmapsPlugin extends PluginActivator implements TopicmapsService, PostInstallPluginListener {
+public class TopicmapsPlugin extends PluginActivator implements TopicmapsService, InitializePluginListener,
+ AllPluginsActiveListener {
// ------------------------------------------------------------------------------------------------------- Constants
@@ -61,14 +63,6 @@
- public TopicmapsPlugin() {
- // Note: registering the default renderer in the InitializePluginListener would be too late.
- // The renderer is already needed in the PostInstallPluginListener.
- registerTopicmapRenderer(new DefaultTopicmapRenderer());
- }
-
-
-
// ***************************************
// *** TopicmapsService Implementation ***
// ***************************************
@@ -82,6 +76,8 @@ public Topicmap getTopicmap(@PathParam("id") long topicmapId, @HeaderParam("Cook
return new Topicmap(topicmapId, dms, clientState);
}
+ // ---
+
@POST
@Path("/{name}/{topicmap_renderer_uri}")
@Override
@@ -95,6 +91,12 @@ public Topic createTopicmap(@PathParam("name") String name,
), null); // FIXME: clientState=null
}
+ @Override
+ public void registerTopicmapRenderer(TopicmapRenderer renderer) {
+ logger.info("### Registering topicmap renderer \"" + renderer.getClass().getName() + "\"");
+ topicmapRendererRegistry.put(renderer.getUri(), renderer);
+ }
+
// ---
@POST
@@ -121,14 +123,12 @@ public void addAssociationToTopicmap(@PathParam("id") long topicmapId, @PathPara
), 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()
+ fetchTopicRefAssociation(topicmapId, topicId).setCompositeValue(new CompositeValue()
.put("dm4.topicmaps.x", x)
.put("dm4.topicmaps.y", y), null, new Directives()); // clientState=null
}
@@ -138,21 +138,17 @@ public void moveTopic(@PathParam("id") long topicmapId, @PathParam("topic_id") l
@Override
public void setTopicVisibility(@PathParam("id") long topicmapId, @PathParam("topic_id") long topicId,
@PathParam("visibility") boolean visibility) {
- getTopicRefAssociation(topicmapId, topicId).setCompositeValue(new CompositeValue()
+ fetchTopicRefAssociation(topicmapId, topicId).setCompositeValue(new CompositeValue()
.put("dm4.topicmaps.visibility", visibility), null, new Directives()); // clientState=null
}
- // ---
-
@DELETE
@Path("/{id}/association/{assoc_id}")
@Override
public void removeAssociationFromTopicmap(@PathParam("id") long topicmapId, @PathParam("assoc_id") long assocId) {
- getAssociationRefAssociation(topicmapId, assocId).delete(new Directives());
+ fetchAssociationRefAssociation(topicmapId, assocId).delete(new Directives());
}
- // ---
-
@PUT
@Path("/{id}/translation/{x}/{y}")
@Override
@@ -169,20 +165,12 @@ public void setTopicmapTranslation(@PathParam("id") long topicmapId, @PathParam(
// ---
- @Override
- public void registerTopicmapRenderer(TopicmapRenderer renderer) {
- logger.info("### Registering topicmap renderer \"" + renderer.getClass().getName() + "\"");
- topicmapRendererRegistry.put(renderer.getUri(), renderer);
- }
-
- // ---
-
// Note: not part of topicmaps service
@GET
@Path("/{id}")
@Produces("text/html")
public InputStream getTopicmapInWebclient() {
- // Note: the template parameter is evaluated at client-side
+ // Note: the path parameter is evaluated at client-side
return invokeWebclient();
}
@@ -191,7 +179,7 @@ public InputStream getTopicmapInWebclient() {
@Path("/{id}/topic/{topic_id}")
@Produces("text/html")
public InputStream getTopicmapAndTopicInWebclient() {
- // Note: the template parameters are evaluated at client-side
+ // Note: the path parameters are evaluated at client-side
return invokeWebclient();
}
@@ -204,20 +192,31 @@ public InputStream getTopicmapAndTopicInWebclient() {
@Override
- public void postInstallPlugin() {
- createTopicmap(DEFAULT_TOPICMAP_NAME, DEFAULT_TOPICMAP_RENDERER);
+ public void initializePlugin() {
+ registerTopicmapRenderer(new DefaultTopicmapRenderer());
+ }
+
+ @Override
+ public void allPluginsActive() {
+ // create default topicmap if no one exists
+ if (dms.searchTopics(DEFAULT_TOPICMAP_NAME, "dm4.topicmaps.name", true, null).size() == 0) { // wholeWord=true
+ // Note: naturally we would create the default topicmap in the PostInstallPluginListener.
+ // But we defer it to the AllPluginsActiveListener to ensure the Access Control plugin is ready.
+ // The default topicmap needs ACL entries and creator information.
+ createTopicmap(DEFAULT_TOPICMAP_NAME, DEFAULT_TOPICMAP_RENDERER);
+ }
}
// ------------------------------------------------------------------------------------------------- Private Methods
- private Association getTopicRefAssociation(long topicmapId, long topicId) {
+ private Association fetchTopicRefAssociation(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) {
+ private Association fetchAssociationRefAssociation(long topicmapId, long assocId) {
return dms.getAssociationBetweenTopicAndAssociation(ASSOCIATION_MAPCONTEXT, topicmapId, assocId,
ROLE_TYPE_TOPICMAP, ROLE_TYPE_ASSOCIATION, false, null); // fetchComposite=false, clientState=null
}
@@ -13,29 +13,23 @@
Topicmap getTopicmap(long topicmapId, ClientState clientState);
+ // ---
+
Topic createTopicmap(String name, String topicmapRendererUri);
+ void registerTopicmapRenderer(TopicmapRenderer renderer);
+
// ---
void addTopicToTopicmap(long topicmapId, long topicId, int x, int y);
void addAssociationToTopicmap(long topicmapId, long assocId);
- // ---
-
void moveTopic(long topicmapId, long topicId, int x, int y);
void setTopicVisibility(long topicmapId, long topicId, boolean visibility);
- // ---
-
void removeAssociationFromTopicmap(long topicmapId, long assocId);
- // ---
-
void setTopicmapTranslation(long topicmapId, int trans_x, int trans_y);
-
- // ---
-
- void registerTopicmapRenderer(TopicmapRenderer renderer);
}
@@ -4,7 +4,7 @@
value: "Name",
uri: "dm4.topicmaps.name",
data_type_uri: "dm4.core.text",
- index_mode_uris: ["dm4.core.fulltext"]
+ index_mode_uris: ["dm4.core.fulltext", "dm4.core.fulltext_key"]
},
{
value: "Description",
@@ -1,3 +1,3 @@
requiredPluginMigrationNr = 3
-providedServiceInterface = de.deepamehta.plugins.topicmaps.service.TopicmapsService
importModels = de.deepamehta.webclient, de.deepamehta.files
+providedServiceInterface = de.deepamehta.plugins.topicmaps.service.TopicmapsService
View
@@ -152,7 +152,9 @@
<artifactId>umlgraph</artifactId>
<version>5.6</version>
</docletArtifact>
- <additionalparam>-collapsible -hide java.* -hide org.* -inferdepvis public -inferrel</additionalparam>
+ <additionalparam>
+ -collapsible -hide java.* -hide org.* -inferdepvis public -inferrel
+ </additionalparam>
<useStandardDocletOptions>true</useStandardDocletOptions>
</configuration>
</plugin>

0 comments on commit 2d202ca

Please sign in to comment.