Ticket #904 (new Defect)

Opened 5 years ago

Last modified 4 years ago

ChildTopics set() method does not work as expected for multiple-valued composite childs

Reported by: Malte Owned by:
Priority: Major Milestone: Release 4.8
Component: DeepaMehta Standard Distribution Version: 4.7
Keywords: Cc: jri
Complexity: 3 Area:
Module:

Description

The core source documentation (as well as the hint in #805#comment:1) says:

    /**
     * Convenience method to set the composite value of a child.
     * Works for both, single-valued child and multiple-valued child (cardinality "many").
     */
    ChildTopics set(String childTypeUri, ChildTopicsModel value);

Now if trying it out, like:

ChildTopicsModel actionReportModel = new ChildTopicsModel()
    .putRef(SCREEN_ACTION_NAME_TYPE, actionNameUri)
    .put(SCREEN_ACTION_VALUE_TYPE, actionValue);
existingReport.getChildTopics().set(SCREEN_ACTION_TYPE, actionReportModel);

The following error is thrown:

SCHWERWIEGEND: A DeepaMehta resource method or event listener threw an exception resp. an error occurred. Mapping exception/error to response: 500 (Internal Server Error).
java.lang.RuntimeException: Updating the child topics of topic 9804 failed (newComp={de.akmiraketen.screen_action=topic (id=-1, uri="null", typeUri="de.akmiraketen.screen_action", value="null", childTopics={de.akmiraketen.action_name=topic (id=-1, uri="de.akmiraketen.select", typeUri="null", value="null", childTopics={}), de.akmiraketen.action_value=topic (id=-1, uri="null", typeUri="de.akmiraketen.action_value", value="{"name":"Ladenzeile","type":"shop","id":"8982C70A-EFED-7F5F-85BC-95C7C0754911"}", childTopics={})})})
	at de.deepamehta.core.impl.AttachedChildTopics.update(AttachedChildTopics.java:221)
	at de.deepamehta.core.impl.AttachedDeepaMehtaObject.updateValue(AttachedDeepaMehtaObject.java:370)
	at de.deepamehta.core.impl.AttachedDeepaMehtaObject.update(AttachedDeepaMehtaObject.java:185)
	at de.deepamehta.core.impl.AttachedChildTopics._update(AttachedChildTopics.java:331)
	at de.deepamehta.core.impl.AttachedChildTopics.set(AttachedChildTopics.java:166)
	at de.akmiraketen.plugins.experiments.WebExperimentsPlugin.addActionReport(WebExperimentsPlugin.java:373)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
	at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:205)
	at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
	at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:302)
	at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
	at com.sun.jersey.server.impl.uri.rules.ResourceObjectRule.accept(ResourceObjectRule.java:100)
	at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
	at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
	at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1480)
	at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1411)
	at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1360)
	at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1350)
	at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416)
	at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:538)
	at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:716)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:684)
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:503)
	at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:69)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137)
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:557)
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1086)
	at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:240)
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:429)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1020)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
	at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:77)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
	at org.eclipse.jetty.server.Server.handle(Server.java:370)
	at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:494)
	at org.eclipse.jetty.server.AbstractHttpConnection.content(AbstractHttpConnection.java:982)
	at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.content(AbstractHttpConnection.java:1043)
	at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:865)
	at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:240)
	at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)
	at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:696)
	at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:53)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.RuntimeException: Invalid access to ChildTopicsModel entry "de.akmiraketen.screen_action": the caller assumes it to be multiple-value but it is single-value in
{de.akmiraketen.screen_action=topic (id=-1, uri="null", typeUri="de.akmiraketen.screen_action", value="null", childTopics={de.akmiraketen.action_name=topic (id=-1, uri="de.akmiraketen.select", typeUri="null", value="null", childTopics={}), de.akmiraketen.action_value=topic (id=-1, uri="null", typeUri="de.akmiraketen.action_value", value="{"name":"Ladenzeile","type":"shop","id":"8982C70A-EFED-7F5F-85BC-95C7C0754911"}", childTopics={})})}
	at de.deepamehta.core.model.ChildTopicsModel.throwInvalidAccess(ChildTopicsModel.java:585)
	at de.deepamehta.core.model.ChildTopicsModel.getTopics(ChildTopicsModel.java:131)
	at de.deepamehta.core.impl.AttachedChildTopics.update(AttachedChildTopics.java:206)
	... 51 more
Caused by: java.lang.ClassCastException: de.deepamehta.core.model.TopicModel cannot be cast to java.util.List
	at de.deepamehta.core.model.ChildTopicsModel.getTopics(ChildTopicsModel.java:128)
	... 52 more

Dez 04, 2015 1:43:11 PM de.deepamehta.core.impl.TransactionFactory$TransactionResourceFilter$2 filter
WARNUNG: ### Rollback transaction of AbstractSubResourceMethod(WebExperimentsPlugin#addActionReport)

The same happens when (i create the intermediary ChildTopic?) like this. Afaik to create this (intermediary) parent child topic should not be needed (as everything would be expressed already in the code i used in the first try, see above):

            ChildTopicsModel actionReportChilds = new ChildTopicsModel()
                    .putRef(SCREEN_ACTION_NAME_TYPE, actionNameUri)
                    .put(SCREEN_ACTION_VALUE_TYPE, actionValue);
            ChildTopicsModel actionReportTopic = new ChildTopicsModel()
                    .put(SCREEN_ACTION_TYPE, actionReportChilds);
            existingReport.getChildTopics().set(SCREEN_ACTION_TYPE, actionReportTopic);
            return Response.ok(OK_NR).build();

The underlying type def here is: The existingReport Topics type def composes many actionReports which in turn aggrgates one name and composes one value.

What am i doing wrong? :) And is it just the log message which misleads me )which we might have discussed elswhere) because the expression stated in ther can not correspond to the type def of "existingReport)?
Thanks for any clarification.

Change History

comment:1 Changed 5 years ago by Malte

Now, doing it the manual way, this worked for me:

ChildTopicsModel actionReportChilds = new ChildTopicsModel()
    .putRef(SCREEN_ACTION_NAME_TYPE, actionNameUri)
    .put(SCREEN_ACTION_VALUE_TYPE, actionValue);
ChildTopicsModel actionReportTopic = new ChildTopicsModel()
    .add(SCREEN_ACTION_TYPE, new TopicModel(SCREEN_ACTION_TYPE, actionReportChilds));
TopicModel actionReportModel = new TopicModel(SCREEN_REPORT_TYPE, actionReportTopic);
existingReport.update(actionReportModel);

Would be great if we could improve on the convenience call up to the point that the (first level intermediary composite topic) is created automatically through looking up if its a child type (and of type composite) of the ChildTopic? on which .set() is called. From a plugin developers perspective the following three lines are redundant:

ChildTopicsModel actionReportTopic = new ChildTopicsModel()
    .add(SCREEN_ACTION_TYPE, new TopicModel(SCREEN_ACTION_TYPE, actionReportChilds));
TopicModel actionReportModel = new TopicModel(SCREEN_REPORT_TYPE, actionReportTopic);

Since all the involved type definitions (related to each other) are declared in the following three lines.

ChildTopicsModel actionReportModel = new ChildTopicsModel()
    .putRef(SCREEN_ACTION_NAME_TYPE, actionNameUri)
    .put(SCREEN_ACTION_VALUE_TYPE, actionValue);
existingReport.getChildTopics().set(SCREEN_ACTION_TYPE, actionReportModel);

So these four lines should be enough for a plugin developer to achieve the same results.

comment:2 Changed 4 years ago by Malte

Since we can always reason about new possibilities for API simplification, the point made in my latest comment is:

SCREEN_REPORT_TYPE (in the last comment) is the typeUri of a data type "dm4.core.composite" topic which (itself has no direct values) but it has SCREEN_ACTION_NAME and SCREEN_ACTION_TYPE as child types.

When the type hierarchy is:

Screen Report (Composite)
   Screen Action Report (Composite, Many)
      Screen Action Name (Text, One)
      Screen Action Value (Text, One)

and doesn't it make sense (wouldnt everything be said) if a plugin dev could just state:

ScreenReport.set(ChildTopics(put(Screen Action Name), putRef(Screen Action Type)));

to add anohter "Screen Action Report" to "Screen Report"?

Just some thoughts. Thanks for your time & Cheers!

Note: See TracTickets for help on using tickets.