POMs: bump version number to 4.1.1-SNAPSHOT
Extend 2 test cases about comp values and labels
Update COPYRIGHT.txt (#434).

"Copyright 2000-2013 Jörg Richter et al."

Close ticket 434.
Access Control module: fix logout (#423).

Logout works for "private" DM installations too.

As a reminder:
The webclient of a "private" DM installation is only be visible/usable when logged in. The browser brings up its own login dialog *before* the DM Webclient actually appears. And once logged out, the Webclient GUI disappears and leaves a blank browser window.
A DM installation is made "private" by setting the `dm4.security.read_requires_login` config property to `true`. See
    pom.xml (Development setup)
    /conf/config.properties (Standard Distribution)
    /etc/system.properties (Karaf Distribution)
By default the Standard Distribution sets up "non-private" DM installation.
By default the Karaf Distribution sets up a "private" DM installation.

To fight the "HTTP logout" problem in conjunction with a "private" DM installation the following workaround is now utilized: a /accesscontrol/logout request replies with 401 Authorization Required. This emulates a HTTP logout by forcing the webbrowser to bring up its login dialog. This time the login dialog is pure dummy (it can't be used to login again). The login dialog just forces the browser to forget the former Authorization information. The user is supposed to press "Cancel". The webclient shuts down the GUI then and the browser window just shows "You're logged out now".

At the moment the login dialog appears the user is actually logged out already (the session is invalidated), so it is safe to close the browser window immediately, without pressing "Cancel".

In the browser's error console the 401 response is reported as an error. This can safely be ignored.

The dummy login dialog appears at least in Firefox and Chrome. However, in Safari (tested with 5.1.7 as of Mac OS X 10.6.8 Snow Leopard) the dummy login dialog does *not* appear. Apparently Safari suppresses the login dialog when the 401 is a result of an AJAX request.

Conclusion: with Safari logging out from a "private" DM installation works perfectly fine (besides a 401 error is reported). With Firefox and Chrome the possibility of a true HTTP logout comes at the price of a dummy login dialog. With a "non-private" DM installation logout is no problem at all.

This ticket is regarded as resolved.

BREAKING CHANGE

Access Control API:
    - logout() (resp. /accesscontrol/logout) returns void (instead of boolean).
      For a "private" DM installation the response is 401 Authorization Required.

See ticket 423.
Webclient: revise topicmap view model (#443).

The default topicmap view model is now renderer agnostic.
It is not coupled to a HTML5 Canvas 2D Context anymore.

BREAKING CHANGES

DefaultTopicmapRenderer.Model
    - class is renamed to DefaultTopicmapViewmodel
    - add_topic() returns the created topic view model (formerly void)
    - add_association() returns the created association view model (formerly void)

Canvas Topic (the topic view model):
    - "truncated_label" is a new property

Close ticket 443.
Karaf distro: standard distro defaults (#447).

The DM Karaf distro uses same default configuration as the DM Standard Distro.

- dm4.security.read_requires_login: false
- dm4.security.subnet_filter: 127.0.0.1/32

Close ticket 447.
Webservice: generic JSON provider (#277, #278).

The Webservice module now offers a generic MessageBodyReader Provider for JSON reprensented entities (#277).
This means the application developer must no longer implement a custom provider class when she wants to deserialze an arbitrary JSON represented application object contained in the message body. She only must ensure the application object's class has a public constructor that takes a JSONObject as argument.
In other words: in your (REST) resource methods you can use an arbitrary class as the type of the entity parameter as long as the entity is represented in JSON and the class has a public JSON constructor. You are no longer required to implement a provider class.

Furthermore: the webservice's provider classes are generalized by exploting the fact that most DM core application objects implements the JSONEnabled interface. 6 provider classes are stripped from the webservice module (#278).

BREAKING CHANGES

DeepaMehtaUtils
    - relatedTopicsToJson() deleted

See ticket 277.
See ticket 278.
Consolidate JAX-RS provider classes (#277, #278).

Exception handling:
All provider classes throw a WebApplicationException.

Access Control Plugin:
"Permissions" provider class is deleted (it is not needed).

Close ticket 277.
Close ticket 278.
Core: generic property handling methods (#472).

The DeepaMehta Core service provides 3 new methods for handling generic properties:
    - getProperty()
    - setProperty()
    - hasProperty()

AccessControl service:
    - getACL() is new method

BREAKING CHANGES

DeepaMehta Core service:
    - 6 methods are dropped:
        - getACL()
        - setACL()
        - getCreator()
        - setCreator()
        - getOwner()
        - setOwner()
      Use the AccessControl service instead

AccessControl:
    - 4 classes have moved from package de.deepamehta.core.service.accesscontrol to
                                        de.deepamehta.plugins.accesscontrol.model:
        - AccessControlList
        - ACLEntry
        - Operation
        - UserRole
      You must adapt your imports.

See ticket 472.
New dm4-time plugin: store timestamps (#386).

"DeepaMehta 4 Time" is a new plugin.
Belongs to the DeepaMehta Standard Distribution.

For every topic and association 2 database properties are maintained:
    - "created"
    - "modified"

For readability timestamps are stored in IETF-compliant RFC 2822 format with a fixed GMT/UTC timezone.
Example:
    Tue, 04 Jun 2013 00:23:16 GMT
See http://tools.ietf.org/html/rfc2822#section-3.3

Note: you can investigate the timestamps via the Neo4j Shell.
Example:

    mvn exec:java -P neo4j

    neo4j-sh[readonly] (0)$ ls 2695

        *node_type =[topic]
        *uri       =[]
        *type_uri  =[dm4.notes.note]
        *value     =[T1]

        *created   =[Tue, 04 Jun 2013 00:23:16 GMT]
        *modified  =[Tue, 04 Jun 2013 00:23:40 GMT]

        *creator   =[admin]
        *owner     =[admin]
        *acl       =[{"WRITE":["CREATOR","OWNER","MEMBER"]}]

See ticket 386.
Access Control: fix login (#473).

No exception occurs if the user enters neither a username nor a password in the login dialog.

Close ticket 473.
Access Control: fix exception logging (#474).

When file logging is activated exceptions thrown from the Access Control's request filter are logged into the log file.

See ticket 474.
Access Control: suppress login dialog (#471).

In a **default DM installation**: the browser's login dialog does not appear anymore when logging in via DM's login dialog failed. You keep staying in DM's login dialog. This applies in particular to Google Chrome.
Bottom line: in a default DM installation the browser's login dialog never appears. Regardless of browser (Safari, Firefox, Chrome).

However, in a **private DM installation** (dm4.security.read_requires_login=true) there is still an issue with logout: in Firefox and Chrome the browser login dialog still appears when clicking the Logout link. Remember: this dialog is a "dummy", you can press Cancel and you're logged out properly.

See ticket 471.
Access Control: fix login (#475).

Login works also with an open DM installation.

An open DM installation is one with
    dm4.security.read_requires_login=false
    dm4.security.write_requires_login=false

Close ticket 475.
REST Client: send asynchronous requests (#476).

Plugins providing a REST service can send the respective requests asynchronously.

BREAKING CHANGE

REST Client: the dm4c.restc.request() method has an additional "callback" parameter (the 4th parameter).

    request = function(method, uri, data, callback, headers, response_data_type)

Description of the "callback" parameter:
    Optional: the function to be called if the request is successful.
    One argument is passed: the data returned from the server.
    If not specified, the request is send synchronously.

If your plugins uses that method with more than 3 parameters -- that is if you pass "headers" or "response_data_type" you must adapt the respective calls. To keep your plugin's current request semantic -- that is **synchronous** requests -- pass undefined as the 4th parameter.
However, very few plugins should be affected.

Close ticket 476.
New Core Event PRE_SEND_RESPONSE (#477, #386).

Fired before the response is send to the client. That is exactly once per request.
This allows plugins to set certain response headers like `Last-Modified`.

New listener interface:
    de.deepamehta.core.service.event.PreSendResponseListener
Listener method:
    void preSendResponse(ContainerResponse response)

Note: ContainerResponse is a Jersey-specific class (com.sun.jersey.spi.container.ContainerResponse).
We should remove the Jersey dependency and move to JAX-RS 2.0 instead.

See ticket 477.
See ticket 386.
Time Plugin: send Last-Modified headers (#386).

If the response contains a single entity and if a `modified` timestamp for that entity is stored in the DB the `Last-Modified` response header is set accordingly.

The Time plugin provides an OSGi service (no REST service yet):
    - String getTimeCreated(long objectId)
    - String getTimeModified(long objectId)

See ticket 386.
New Core Event PRE_PROCESS_REQUEST (#480, #478).

Fired before a request is processed. That is *before* a possible resource method is invoked.
This allows a plugin e.g. to abort request processing in case a pre-condition is not met (as stated e.g. by the `If-Modified-Since` or `If-Unmodified-Since` headers).

New listener interface:
    de.deepamehta.core.service.event.PreProcessRequestListener
Listener method:
    void preProcessRequest(ContainerRequest request)

Note: ContainerRequest is a Jersey-specific class
(com.sun.jersey.spi.container.ContainerRequest).
We should remove the Jersey dependency and move to JAX-RS 2.0 instead.

Close ticket 480.
See ticket 478.
Time plugin: change storage format (#386).

The timestamps are stored in Unix time. The Time API has changed accordingly.
This is to better support range queries in the future.

If you've already installed the Time plugin you should reset your DB.

See ticket 386.
Core: listener exception handling (#481).

A WebApplicationException thrown by a event listener reach Jersey.
This allow plugins to produce specific HTTP responses by throwing a WebApplicationException.

Close ticket 481.