Ticket #941 (accepted Task)

Opened 4 years ago

Last modified 3 years ago

Consolidate Core API

Reported by: jri Owned by: jri
Priority: Major Milestone: Release 4.8
Component: DeepaMehta Standard Distribution Version: 4.7
Keywords: Cc: dgf, Malte, JuergeN, robert.schuster
Complexity: 3 Area: Application Framework / API
Module:

Description (last modified by jri) (diff)

Meanwhile the (REST) APIs of the Core and the standard plugins are quite stable. However, some namings resp. request formats could be improved. One of the upcoming DM releases should consolidate the class/method namings and request formats. This is regarded a prerequisite for the to-be-written extensive DM Development Guide (see #444).

List of intended API changes:

  • The DeepaMehtaService interface should be named CoreService. Consequently the omnipresent dms object should be named cs.
  • The DeepaMehtaService's deliverEvent() method should be named dispatchEvent().
  • The DeepaMehtaService's various getTopic[s] methods possibly could have more telling names, e.g. getTopicById().
  • The ChildTopicModel's getTopic[s] methods should have the same form as its counterparts in ChildTopics. The forms that take default value should be transformed into getTopic[s]OrNull (that is a fixed default value of null). All forms should catch and report a ClassCastException.
  • to be continued ... you proposals here ...

Change History

comment:1 Changed 4 years ago by jri

  • Status changed from new to accepted

comment:2 Changed 4 years ago by jri

  • Description modified (diff)
  • Summary changed from Consolidate API wording to Consolidate Core API

comment:3 Changed 4 years ago by Jörg Richter <jri@…>

In ac219a5883f74725afdb9bf90755d57172c3d99b/deepamehta:

Core: revise ChildTopicsModel? getters (#941).

BREAKING CHANGES

3 method changes in ChildTopicsModel:

Since DM 4.8 the ChildTopicModel's getTopic[s] methods have the same form as their counterparts in ChildTopics.

The 2 getters which took a defaultValue parameter are now called getTopic[s]OrNull.
The defaultValue parameter is dropped. null is used as the default value.

RelatedTopicModel getTopic(String assocDefUri, RelatedTopicModel defaultValue);
-->
RelatedTopicModel getTopicOrNull(String assocDefUri);
List<RelatedTopicModel> getTopics(String assocDefUri, List<RelatedTopicModel> defaultValue);
-->
List<? extends RelatedTopicModel> getTopicsOrNull(String assocDefUri);

Note the changed return type of the 2 plural forms (getTopics...).

List<RelatedTopicModel> getTopics(String assocDefUri);
-->
List<? extends RelatedTopicModel> getTopics(String assocDefUri);

See #941.

comment:4 Changed 4 years ago by Jörg Richter <jri@…>

In 09ff9c7ef7960a5a8688b2bf9e05ece136722b79/deepamehta:

Core/Workspaces? API: change by-type calls (#941).

BREAKING CHANGES

Core API

The 2 "get-by-type" methods have changed:

ResultList<RelatedTopic> getTopics(String topicTypeUri)
->
List<Topic> getTopics(String topicTypeUri)

The result type is a plain List now.
As a consequence you have to call size() now (instead of getSize()).

This affects also the REST API: the result array is returned directly.
You must not refer to .items anymore.

Dito for associations:

ResultList<RelatedAssociation> getAssociations(String assocTypeUri)
->
List<Association> getAssociations(String assocTypeUri)

Note that at the moment this call has no corresponding REST API.

Workspaces API

The 2 "get-assigned" methods which have a type filter, and the corresponding REST API responses, have changed accordingly:

ResultList<RelatedTopic> getAssignedTopics(long workspaceId, String topicTypeUri)
->
List<Topic> getAssignedTopics(long workspaceId, String topicTypeUri)
ResultList<RelatedAssociation> getAssignedAssociations(long workspaceId, String assocTypeUri)
->
List<Association> getAssignedAssociations(long workspaceId, String assocTypeUri)

Summary of the affected REST API:

GET /core/topic/by_type/{topic_type_uri}

GET /workspace/{id}/topics/{topic_type_uri}
GET /workspace/{id}/assocs/{assoc_type_uri}

See #941.

comment:5 Changed 4 years ago by Jörg Richter <jri@…>

In 9bb4d90eaa22884764f3b04a5ce9ccf870d2a7c8/deepamehta:

Core API: DeepaMehtaService? wording (#941).

BREAKING CHANGES

Core API

1 interface renamed:

de.deepamehta.core.service.DeepaMehtaService
->
de.deepamehta.core.service.CoreService

1 object renamed:

dms -> dm4

Background: the wording DeepaMehtaService was not concise. What would be the DeepaMehtaService?? Possibly the wholeness of all the DeepaMehta module services. But such an entity does not exist.

CoreService on the other hand denotes exactly what it is: the service of the DeepaMehta Core module.

Consequently dms is no longer a suitable name. A candidate would be cs then. However with the new dm4 wording an exception was made as this omnipresent object is of central importance for every DeepaMehta developer.

See #941.

comment:6 Changed 4 years ago by Jörg Richter <jri@…>

In f7efd80ed860c706a79c9432748d6f246a53ecbb/deepamehta:

Core API: drop class ResultList (#941).

BREAKING CHANGES

Core API

1 class dropped:

de.deepamehta.core.service.ResultList

Since DM 4.8 all methods which returned a ResultList now return a plain java.util.List.

Background: ResultList once was instroduced in conjunction with the "Result Limit" feature but that feature is abandoned for quite a while (see #895). This makes the API uniform as the develper must no longer treat ResultList and List results differently.

1 new method in DeepaMehtaUtils:

public static <T extends DeepaMehtaObject> List<T> loadChildTopics(List<T> objects)

Before 4.8 this method was located in ResultList? and is now a static utility.

REST API

As a consequence all responses which returned a "ResultList?" now return the plain result array.

Pre-4.8 response:

{
    items: [...]
}

Since 4.8:

[...]

3rd-party clients (which do not rely on the Webclient's rest_client.js) must be adapted.

These REST API calls are affected:

Core

GET /core/topic/{id}/related_topics
GET /core/topic/{id}/related_assocs
GET /core/association/{id}/related_topics
GET /core/association/{id}/related_assocs

Webclient

GET /webclient/topic/{id}/related_topics

Contacts

GET /contact/{id}/institutions
GET /contact/{id}/persons

Events

GET /event/participant/{id}
GET /event/{id}/participants

Factes

GET /facet/multi/{facet_type_uri}/topic/{id}

See #941.

comment:7 Changed 4 years ago by Jörg Richter <jri@…>

In cda2fd7dae6c05d86be453edddf61e5132f1d4b0/deepamehta:

Adapt webclient to dropped ResultList (#941).

See #941.

comment:8 follow-ups: ↓ 11 ↓ 12 Changed 4 years ago by Malte

On thing came to my mind about API wording:

I struggled to understandd the meaning of has() as a method of ChildTopics? in respective to the Storage Layer (as of the concept when working with "attached" topics) it always seemed unclear to me if has checked if a specific composite topic :

  • has this child topic at all (in the db) or
  • has this child already loaded (from the db)

I would suspect that has() checks in the DB if such a child topic is existing (and not if it is loaded).
http://api.deepamehta.de/deepamehta/4.7/de/deepamehta/core/ChildTopics.html

And BTW just because this just changed:
In the DeepaMehtaUtils?.loadChildTopics() we still need the ability to load specific child selectively :)

Thanks & Cheers!

comment:9 Changed 4 years ago by Jörg Richter <jri@…>

In 9a93d93ae6afd6eb6a83e0e21d1ac3e920f6400c/deepamehta:

Core API: rename deliverEvent() (#941).

BREAKING CHANGE

1 method renamed in CoreService:

deliverEvent(..) -> dispatchEvent(..)

If your plugin calls dms.deliverEvent(..) it must be adapted.

1 method renamed in DeepaMehtaEvent:

deliver(..) -> dispatch(..)

If your plugin defines custom events it must be adapted.

See #941.

comment:10 Changed 4 years ago by Jörg Richter <jri@…>

In 387c0f35a995fe42cd2caa787c29d0a526839bb1/deepamehta:

Core API: rename getTopic(key, value) (#941).

BREAKING CHANGE

1 Core service method renamed:

Topic getTopic(String key, SimpleValue value)
->
Topic getTopicByValue(String key, SimpleValue value)

Formerly the getTopic() method was overloaded.
Not anymore. The wording is more informative now.

The REST API hasn't changed.

See #941.

comment:11 in reply to: ↑ 8 Changed 4 years ago by jri

Replying to Malte:

I struggled to understandd the meaning of has() as a method of ChildTopics? in respective to the Storage Layer (as of the concept when working with "attached" topics) it always seemed unclear to me if has checked if a specific composite topic :

  • has this child topic at all (in the db) or
  • has this child already loaded (from the db)

I would suspect that has() checks in the DB if such a child topic is existing (and not if it is loaded).

Actually the other applies.
ChildTopics has() checks if a certain child topic(s) is loaded into memory.

Indeed, the "has" wording is not lucky.
The same applies btw to the size() method. It tells you how many child topics are loaded.

Note that since DM 4.1 loading child topics is transparent to the plugin developer. On a ChildTopics object she just calls getTopic[s]() and the Core cares about on-demand loading.

Do you actually use has() or size() in your plugins?

Actually I can't think of any case when a plugin developer needs to know wether a certain child topic(s) is loaded into memory. Meanwhile (in the course of DM 4.8) I see has() and size() as Core internal and tend to completely remove them from the public Core API.

Thank you for pointing to this problematic API!

comment:12 in reply to: ↑ 8 Changed 4 years ago by jri

Replying to Malte:

And BTW just because this just changed:
In the DeepaMehtaUtils?.loadChildTopics() we still need the ability to load specific child selectively :)

Before DM 4.8 you can call loadChildTopics() on a ResultList object. It loads all child topics of all the objects in the ResultList?. Since DM 4.8 the ResultList class is dropped and so its loadChildTopics() utility method needed a new home, which is DeepaMehtaUtils. Note that DeepaMehtaUtils?.loadChildTopics() takes a List as argument.

At the moment I can't think of a case when you want load a specific child topic of all the objects in a List. At least this was never supported by ResultList's loadChildTopics() method. (If you need such a utility you can easily write it yourself).

DeepaMehtaObject (and thus Topic and Association) still provides both (and possibly this is what you meant):

loadChildTopics();                    // loads all childs
loadChildTopics(String assocDefUri);  // loads specific child

Generally explicit child topics loading is something rarely needed by a plugin developer as in most cases it is done automatically by the Core.

comment:13 Changed 4 years ago by Jörg Richter <jri@…>

In dd82f0afa7757ce85663c81ea27be29370945d3d/deepamehta:

Core API: rename getTopics() (#941).

BREAKING CHANGE

2 Core service methods renamed:

List<Topic> getTopics(String key, SimpleValue value)
->
List<Topic> getTopicsByValue(String key, SimpleValue value)
List<Topic> getTopics(String topicTypeUri)
->
List<Topic> getTopicsByType(String topicTypeUri)

Formerly the getTopics() method was overloaded. Not anymore.
The wording is more informative now.

The REST API hasn't changed.
Webclient's rest_client.js hasn't changed.

See #941.

comment:14 Changed 4 years ago by Jörg Richter <jri@…>

In 1c3772da29683f085e0a3a20888efc863edffda7/deepamehta:

Core API: rename getAssociation[s]() (#941).

BREAKING CHANGE

3 Core service methods renamed:

Association getAssociation(String key, SimpleValue value)
->
Association getAssociationByValue(String key, SimpleValue value)
List<Association> getAssociations(String key, SimpleValue value)
->
List<Association> getAssociationsByValue(String key, SimpleValue value)
List<Association> getAssociations(String assocTypeUri)
->
List<Association> getAssociationsByType(String assocTypeUri)

The wording is more informative now.

The REST API hasn't changed.
Webclient's rest_client.js hasn't changed.

See #941.

comment:15 Changed 4 years ago by Jörg Richter <jri@…>

In 42d706235c8b2b5b854c5e981443d6998c0054ad/deepamehta:

Core: rename plugin properties (#941).

BREAKING CHANGE

The properties in plugin.properties are renamed:

requiredPluginMigrationNr -> dm4.plugin.model_version
pluginPackage             -> dm4.plugin.main_package
importModels              -> dm4.plugin.activate_after

You must adapt your plugins.

See #941.

comment:16 Changed 4 years ago by Jörg Richter <jri@…>

In c9bbeec7e5fb55c3ac4985259eb062302c89345b/deepamehta:

Core API: add findChildTopic() (#941).

1 new method in Topic interface:

Topic findChildTopic(String topicTypeUri)

Searches this topic's child topics for a topic of the given type.
Only the child topics which are already loaded into memory are searched; the DB is not accessed.

The first topic found is returned, according to a depth-first search.
For multiple-value childs the first topic is returned.
If the given type matches this topic directly it is returned immediately.

The search is driven by this topic's type definition. That is child topics which do not adhere
to the type definition are not found.

Returns the found topic, or null.

See #941.

comment:17 Changed 4 years ago by Jörg Richter <jri@…>

In b93ef4e2300a865d67cea5cad4194f96d63236ba/deepamehta:

Core API: remove has() and size() (#941).

BREAKING CHANGES

2 methods dropped from public ChildTopics and ChildTopicsModel API:

boolean has(String assocDefUri)
int size()

These are now Core internal and can still be used in the Core tests, e.g. to test on-demand child topic loading.

Thanks to Malte!

See #941.

comment:18 Changed 4 years ago by Jörg Richter <jri@…>

In 28d4f42fe1a13f65d2bf7fbf25b04ada8c6a1be5/deepamehta:

Core API: rename Type interface (#941).

BREAKING CHANGE

1 interface renamed:

de.deepamehta.core.Type
->
de.deepamehta.core.DeepaMehtaType

Reasons:

  • Type is a term too generic and might clash with java.lang.reflect.Type.
  • DeepaMehtaType is in perfect harmony with DeepaMehtaObject.

See #941.

comment:19 Changed 4 years ago by Jörg Richter <jri@…>

In c97487483edad1ae57c81a88f41c932240e2b679/deepamehta:

Repackage standard plugins (#941).

BREAKING CHANGE

The plugins part is stripped from the de.deepamehta.plugins package hierarchy.
You must adapt your imports e.g. when accessing the standard services.

Examples:

import de.deepamehta.accesscontrol.AccessControlService
import de.deepamehta.workspaces.WorkspacesService
import de.deepamehta.topicmaps.TopicmapsService
import de.deepamehta.geomaps.GeomapsService
...

Reason:

  • plugins has no information value and just deepens the package hierarchy without a need.

See #941.

comment:20 Changed 4 years ago by jri

In https://github.com/jri/deepamehta/commit/e9e95484

Properies files: add spaces around = (#941).

See #941.

comment:21 Changed 4 years ago by Malte

BTW: After adapting many plugins to the new 4.8 API i would not like to go back ever again. Great work, I mean reading and writing using the api items is much clearer now. imho this was certainly worth all your work and makes me do appreciate refactoring "grown" stuff much more - Thank you very much, great lesson for me just watching.

Ok, all the best & keep it straight!

comment:22 Changed 4 years ago by jri

Thank you very much :-)

comment:23 Changed 4 years ago by Jörg Richter <jri@…>

In eb33f4acf011d3ce172a0536c8b966483ec2563a/deepamehta:

Workspaces: fix exception handling (#941).

See #941.

comment:24 Changed 4 years ago by Jörg Richter <jri@…>

In 3cecd928ddee40e4a2b67c3f26a2dc40e0930a3d/deepamehta:

Java utils: add cookieValue() (#941).

String cookieValue(HttpServletRequest request, String cookieName)

See #941.

comment:25 Changed 4 years ago by Jörg Richter <jri@…>

In bbfaedd232012361f2dfd13039511ebff7d88f11/deepamehta:

Core API: setLabelConfig() returns type (#941).

The TypeModel's setLabelConfig() method returns the TypeModel itself in order to support chaining.

TypeModel?:

TypeModel setLabelConfig(List<String> labelConfig)

TopicTypeModel?:

TopicTypeModel setLabelConfig(List<String> labelConfig)

AssociationTypeModel?:

AssociationTypeModel setLabelConfig(List<String> labelConfig)

See #941.

comment:26 Changed 3 years ago by Jörg Richter <jri@…>

In ea4b0efd414486c4075d45af847a7e1889733cd9/deepamehta:

Core Type API: more methods returns type (#941).

3 DeepaMehtaType methods returns the type itself in order to support call chaining:

DeepaMehtaType setDataTypeUri(String dataTypeUri);

DeepaMehtaType addIndexMode(IndexMode indexMode);

DeepaMehtaType setLabelConfig(List<String> labelConfig);

See #941.

comment:27 Changed 3 years ago by jri

  • Cc robert.schuster added

comment:28 Changed 3 years ago by Jörg Richter <jri@…>

In e849f88768b5f3c84987246cb13b9b3112066640/deepamehta:

Core: rename formal "update" parameters (#941).

In the pre/post-update listeners the newModel parameter is renamed to updateModel.
The wording "newModel" is obsolete.

This is to emphasize the difference between a regular topic/assoc model and an "update model".

An *update model* contains the update data/instructions.
An update model differs from a regular topic/assoc model in 2 aspects:

  • an update model might be partially uninitialized, e.g. in an update model typeUri might be null, which has the meaning of "don't update the type URI; leave it as is". This is called a *partial update*. In contrast a regular topic/assoc model is always fully initialized.
  • an update model might contain refs and deletion-refs. In contrast a regular topic/assoc model never contains refs; they are resolved already.

old:

void preUpdateTopic(      Topic       topic, TopicModel       newModel)
void preUpdateAssociation(Association assoc, AssociationModel newModel)

new:

void preUpdateTopic(      Topic       topic, TopicModel       updateModel)
void preUpdateAssociation(Association assoc, AssociationModel updateModel)

In the post-update listeners the oldModel parameter is renamed to oldTopic/oldAssoc.
The wording "oldModel" is obsolete.

This is to emphasize the fact that the "old" object is a fully initialized model.

old:

void postUpdateTopic(      Topic       topic, TopicModel       newModel, TopicModel       oldModel)
void postUpdateAssociation(Association assoc, AssociationModel newModel, AssociationModel oldModel)

new:

void postUpdateTopic(      Topic       topic, TopicModel       updateModel, TopicModel       oldTopic)
void postUpdateAssociation(Association assoc, AssociationModel updateModel, AssociationModel oldAssoc)

Also in the Core Service's update methods the newModel wording is replaced by updateModel:

void updateTopic(          TopicModel           updateModel)
void updateAssociation(    AssociationModel     updateModel)
void updateTopicType(      TopicTypeModel       updateModel)
void updateAssociationType(AssociationTypeModel updateModel)

Note that all these changes are purely cosmetic; no functionality has changed.
The aim is making the Core API more intuitive and less ambiguous.

In your plugins you should adapt to the new wording, e.g. in your pre/post-update listeners.

See #941.

comment:29 Changed 3 years ago by Jörg Richter <jri@…>

In 81f5283436f639794cda04261b7db66189e8f8c3/deepamehta:

Core: refactor internal Property API (#941).

See #941.

comment:30 Changed 3 years ago by Jörg Richter <jri@…>

In e1d720337292c001159e5e88b2022e68db02d6b3/deepamehta:

Core: extend ViewConfiguration? API (#941).

2 new methods in ViewConfiguration:

Topic getConfigTopic(String configTypeUri)

Topic addConfigTopic(TopicModel configTopic)

See #941.

comment:31 Changed 3 years ago by Jörg Richter <jri@…>

In c3ef7cb4cc4ffd0037a8d8fa2618ff6a1be30bb4/deepamehta:

Core: revise ViewConfiguration? API (#941).

BREAKING CHANGES

Mostly renamings. 1 method dropped.

1 method renamed in DeepaMehtaType:

getViewConfig(String typeUri, String settingUri)
->
getViewConfigValue(String configTypeUri, String childTypeUri)

2 methods renamed in TypeModel:

getViewConfigModel()
->
getViewConfig()

getViewConfig(String typeUri, String settingUri)
->
getViewConfigValue(String configTypeUri, String childTypeUri)

1 method renamed in ViewConfiguration:

addSetting(String configTypeUri, String settingUri, Object value)
->
setConfigValue(String configTypeUri, String childTypeUri, Object value)

1 method dropped from ViewConfiguration:

updateConfigTopic(TopicModel configTopic)

1 method renamed in ViewConfigurationModel:

getSetting(String configTypeUri, String settingUri)
->
getConfigValue(String configTypeUri, String childTypeUri)

2 convenience methods for migration authors renamed in Migration:

addTopicTypeSetting(...)
addAssociationTypeSetting(...)
->
setTopicTypeViewConfigValue(...)
setAssocTypeViewConfigValue(...)

See #941.

comment:32 Changed 3 years ago by Jörg Richter <jri@…>

In a90192f3f7a256cde648ffc8caf79d108c578b8d/deepamehta:

Core API: getType() has implicit READ perm (#941).

1 DeepaMehtaObject method has changed semantics:

DeepaMehtaType getType()

No access control is performed as Implicit READ permission applies: if a user has
READ access to an object she has READ access to its type as well.

Note: if the user would have no READ access to the object the DeepaMehta Core would not
instantiate it in the first place, but throw an <code>AccessControlException?</code>.

See #941.

comment:33 Changed 3 years ago by Jörg Richter <jri@…>

In 230af24198f7e904301937544e0e63ebfd2463f5/deepamehta:

Core: internal READ access refactoring (#941).

See #941.

comment:34 Changed 3 years ago by Jörg Richter <jri@…>

In dc2790ca51e804657b7ce89efd233ab2ed131091/deepamehta:

Core: refactor meta type handling (#941).

See #941.

comment:35 Changed 3 years ago by Jörg Richter <jri@…>

In 4012b05566f82576a3b6dd517e1602ac28f6d81b/deepamehta:

Core: extend Association API (#941).

4 new convenience methods in Association interface:

/**
 * @return  this association's role that matches the given role type.
 *          If no role matches, null is returned.
 *          If both roles are matching an exception is thrown.
 */
Role getRole(String roleTypeUri);

boolean hasSameRoleTypeUris();

/**
 * Checks if the given players match this association.
 * The given role type URIs must be different.
 * The player position ("1" vs. "2") is not relevant.
 *
 * @return  true if the given players match this association.
 *
 * @throws  IllegalArgumentException    if both given role type URIs are identical.
 */
boolean matches(String roleTypeUri1, long playerId1, String roleTypeUri2, long playerId2);

long getOtherPlayerId(long id);

1 new convenience method in AssociationModel interface:

boolean matches(String roleTypeUri1, long playerId1, String roleTypeUri2, long playerId2);

like above.

See #941.

comment:36 Changed 3 years ago by Jörg Richter <jri@…>

In 894341e304aca8e9c5c28e71d8cace78239aecb4/deepamehta:

Logging: change ABORTED wording to SKIPPED (#941).

See #941.

comment:37 Changed 3 years ago by Jörg Richter <jri@…>

In bdc3e9e4d056d8b89f30020e6b9898f3d2d06f36/deepamehta:

Core API: add RelatedObject? interface (#941).

1 new interface (with 1 method in it):

de.deepamehta.core.RelatedObject

Association getRelatingAssociation();

This is the common interface for both, RelatedTopic and RelatedAssociation.

Needed for upcoming Association API extension.

See #941.

comment:38 Changed 3 years ago by Jörg Richter <jri@…>

In 742e02497977875ccf19dc5f69f9c279c92860ad/deepamehta:

Core Association API: change getTopic() (#941).

BREAKING CHANGE

1 Association method changed:

Topic getTopic(String roleTypeUri)
->
RelatedObject getPlayer(String roleTypeUri)

getPlayer() works for both, Topic players and Association players.
Furthermore the association itself is included in the result as well (as _relating association_), that is you can cast the result to RelatedTopic or RelatedAssociation if you need.

See #941.

Note: See TracTickets for help on using tickets.