Workspaces model: add "Workspace Type" (#592).

Migrations 2 and 3.

See #592.
Add "Workspace Type" selector to dialog (#592).

Not yet functional.

New render helper method:
{{{
dm4c.render.label(label)
}}}

See #592.
Selected "Workspace Type" is persistent (#592).

See #592.
Merge branch 'master' into workspace-acl
Access Control: new permission rule (#592).

Not yet functional.

BREAKING CHANGES

Every workspace must have a "Workspace Type" assigned.
Plugins which introduce its own workspace must be adapted.
See Migration3.java of Workspaces module.

See #592.
Merge branch 'master' into workspace-acl
Access Control: define "Membership" type (#592).

Access Control API

2 new methods:
{{{
void createMembership(String username, long workspaceId)
boolean isMember(String username, long workspaceId)
}}}

BREAKING CHANGES

Each topic/association must be assigned to at maximum *one* workspace.
This applies in particular to "Username" topics.

The "Membership" semantics (that is: a user is a member of one or more workspaces) is now expressed explicitly by means of a "Membership" association (between the "Username" topic and the workspace).

Access Control API

2 methods dropped:
{{{
void joinWorkspace(String username, long workspaceId)
void joinWorkspace(Topic  username, long workspaceId)
}}}
Use `createMembership()` instead (see above).

Workspaces API

1 method changed:
{{{
List<RelatedTopic> getAssignedWorkspaces(DeepaMehtaObject object)
-->          Topic getAssignedWorkspace(DeepaMehtaObject object)
}}}

See #592.
Access Control: READ permission (#592).

The READ permission is enforced per topic/association instance.

Core API

new class:
{{{
de.deepamehta.core.service.AccessControlException
}}}

See #592.
Merge branch 'master' into workspace-acl
Get property w/o fetching the object first (#669).

The `DeepaMehtaService` has 2 new methods:
{{{
Object getProperty(long id, String propUri)
boolean hasProperty(long id, String propUri)
}}}
They access a Topic/Association property without obtaining the Topic/Association object in advance.
The `id` is a Topic ID or an Association ID.

BREAKING CHANGES

The `DeepaMehtaStorage` interface has changed, so storage layer implementations must be adapted.
The Neo4j based implementation is adapted.

See #669.
Store workspace assignment as property (#668).

Thus a topic's/association's workspace assignment can be determined without fetching the topic/association in advance.

BREAKING CHANGES

Workspace API

1 method has changed:
{{{
Topic getAssignedWorkspace(long id)
}}}
It takes a topic/association ID instead of a `DeepaMehtaObject`.

1 method is added:
{{{
Topic createWorkspace(String name, String uri, String workspaceTypeUri)
}}}
So, the workspace type URI must be passed when creating a workspace.
The former 2 `createWorkspace()` methods are dropped.

See #668.
Merge branch 'master' into workspace-acl
Access Control: adapt to PRE_GET semantics (#592).

Topic/Association permissions are checked *before* the Topic/Association is actually instantiated.

See #592.
Core Service: add getPlayerIds() method (#670).

The Core Service provides a new method:
{{{
long[] getPlayerIds(long assocId)
}}}

When an association ID is given it returns the 2 player IDs of that association without
fetching and instantiating a whole `Association` object.

BREAKING CHANGES

The `DeepaMehtaStorage` interface is extended. Storage layer implementations must be adapted.
The Neo4j based implementation is adapted already.

See #670.
Access Control: assoc READ permission (#592).

For the first time a public topicmap which contains partly private objects is properly displayed.

When the user is not logged in the private parts are not displayed, and neither appear in the detail panel.
Once logged in, the private parts appear.

Note: an association is granted READ permission only if the user has READ permission to all the 3 objects: the association itself AND the 2 player topics.

See #592.
Access Control: fix workspace permission (#592).

The READ permission for Workspace topics is calculated properly.

Crucial refactoring: the logic to calculate the permissions has moved from the Access Control module to the Core module. This is required because the permission calculation must involve low-level Core calls (direct storage access) in order to avoid endless recursions. E.g. calculating the READ permission for a workspace topic must be performed without actual fetching the workspace topic itself (through the public Core Service) as this would involve calculating the READ permission...

BREAKING CHANGE

1 class moves to another package:
{{{
de.deepamehta.plugins.accesscontrol.model.Operation
-->
de.deepamehta.core.service.accesscontrol.Operation
}}}

See #592.
Merge branch 'master' into workspace-acl
Fix: default workspace has ACL info (#592).

The default workspace ("DeepaMehta") got creator/owner/ACL information.
The owner information is a requirement for the new workspace ACL rules.
As an additional effect the DeepaMehta workspace topic is now editable by members.

See #592.
Access Control: fix topicmap permission (#592).

The READ permission for Topicmap topics is calculated properly.
The Topicmaps menu shows only topicmaps the user has READ permission for.

See #592.
Access Ctrl: synthesize CREATE permission (#592).

At client-side the CREATE permission is synthesized from both:
    - is the respective type READable?
    - is the current workspace WRITEable?

Note: at client-side the CREATE permission is one factor to decide which types to be shown in the Create menus.

BREAKING CHANGE

At server-side there is no notion of a CREATE permission anymore.
The `Operation.CREATE` enum constant is removed.

See #592.