You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2018/02/09 23:59:15 UTC

[isis] 01/02: ISIS-1585: adds @Action(associateWith=...)

This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch maint-1.16.1
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 7c495c7e5c3b6bbbd2126c29dfc787f71689c7ca
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Fri Feb 9 13:49:01 2018 +0000

    ISIS-1585: adds @Action(associateWith=...)
---
 .../main/asciidoc/guides/rgant/_rgant-Action.adoc  |  6 +++
 .../guides/rgant/_rgant-Action_associateWith.adoc  | 38 ++++++++++++++++
 .../guides/rgant/_rgant-Action_hidden.adoc         |  2 +-
 .../org/apache/isis/applib/annotation/Action.java  | 18 ++++++++
 .../action/ActionAnnotationFacetFactory.java       | 53 ++++++++++++++++++++++
 .../members/order/MemberOrderFacetAbstract.java    | 21 +++++++--
 .../MemberOrderFacetForActionAnnotation.java       | 34 ++++++++++++++
 ...tionFacetFactoryTest_NameAndSequence_parse.java | 43 ++++++++++++++++++
 .../modules/simple/dom/impl/SimpleObject.java      |  3 +-
 .../simple/dom/impl/SimpleObject.layout.xml        |  6 +--
 10 files changed, 212 insertions(+), 12 deletions(-)

diff --git a/adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-Action.adoc b/adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-Action.adoc
index 3d0c422..bac04b4 100644
--- a/adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-Action.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-Action.adoc
@@ -18,6 +18,11 @@ The table below summarizes the annotation's attributes.
 | Description
 
 
+|xref:../rgant/rgant.adoc#_rgant-Action_associateWith[`associateWith()`]
+|_name:sequence_ +
+("")
+|associates an action with another property or collection of the action.
+
 |xref:../rgant/rgant.adoc#_rgant-Action_command[`command()`]
 |`AS_CONFIGURED`, `ENABLED`, `DISABLED` +
 (`AS_CONFIGURED`)
@@ -125,6 +130,7 @@ public class ToDoItem {
 
 
 
+include::_rgant-Action_associateWith.adoc[leveloffset=+1]
 include::_rgant-Action_command.adoc[leveloffset=+1]
 include::_rgant-Action_domainEvent.adoc[leveloffset=+1]
 include::_rgant-Action_hidden.adoc[leveloffset=+1]
diff --git a/adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-Action_associateWith.adoc b/adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-Action_associateWith.adoc
new file mode 100644
index 0000000..913d478
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-Action_associateWith.adoc
@@ -0,0 +1,38 @@
+[[_rgant-Action_associateWith]]
+= `associateWith()`
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or ag [...]
+:_basedir: ../../
+:_imagesdir: images/
+
+
+
+
+The `associateWith` attribute allows an action to be associated with other properties or collections of the same domain object.
+
+For example, an `Order` could have a collection of ``OrderItem``s, and might provide actions to add and remove items:
+
+[source,java]
+----
+public class Order {
+
+    @Collection
+    SortedSet<OrderItem> getItems() { ... }
+
+    @Action(associateWith="items:1")
+    public Order addItem(Product p, int quantity) { ... }
+
+    @Action(associateWith="items:2")
+    public Order removeItem(Product p, int quantity) { ... }
+    ...
+}
+----
+
+These actions - `addItem()` and `removeItem()` can be thought of as associated with with the `items` collection because that is the state that they primarily affect.
+
+In the user interface associated actions are rendered close to the member to which they relate.
+
+[NOTE]
+====
+The same effect can be accomplished using `@MemberOrder` or with the `.layout.xml` file.
+====
+
diff --git a/adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-Action_hidden.adoc b/adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-Action_hidden.adoc
index 1646495..d0b2e99 100644
--- a/adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-Action_hidden.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-Action_hidden.adoc
@@ -7,7 +7,7 @@
 
 
 
-Actions can be hidden at the domain-level, indicating that they are not visible to the end-user.  This attribute can also be applied to xref:../rgant/rgant.adoc#_rgant-Property_hidden[properties] and xref:../rgant/rgant.adoc#_rgant-Collection_hidden[collections].
+Actions can be hidden at the domain-level, indicating that they are not visible to the end-user. This attribute can also be applied to xref:../rgant/rgant.adoc#_rgant-Property_hidden[properties] and xref:../rgant/rgant.adoc#_rgant-Collection_hidden[collections].
 
 [TIP]
 ====
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/Action.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/Action.java
index 17aca49..a415185 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/Action.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/Action.java
@@ -208,4 +208,22 @@ public @interface Action {
     RestrictTo restrictTo() default RestrictTo.NO_RESTRICTIONS;
 
 
+    // //////////////////////////////////////
+
+
+    /**
+     * Associates this action with a property or collection, specifying its id and optionally the order in the UI.
+     *
+     * <p>
+     *     This is an alternative to using {@link MemberOrder#name()}.  To specify the order (equivalent to
+     *     {@link MemberOrder#sequence()}}) add a suffix <code>:XXX</code>.
+     * </p>
+     *
+     * <p>
+     *     For example <code>@Action(associateWith="items:2.1")</code>
+     * </p>
+     */
+    String associateWith() default "";
+
+
 }
\ No newline at end of file
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java
index 03e95e1..a57b8ef 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java
@@ -20,6 +20,9 @@
 package org.apache.isis.core.metamodel.facets.actions.action;
 
 import java.lang.reflect.Method;
+import java.util.regex.Pattern;
+
+import com.google.common.base.Strings;
 
 import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.ActionInteraction;
@@ -81,6 +84,8 @@ import org.apache.isis.core.metamodel.facets.actions.publish.PublishedActionFace
 import org.apache.isis.core.metamodel.facets.actions.semantics.ActionSemanticsFacet;
 import org.apache.isis.core.metamodel.facets.all.hide.HiddenFacet;
 import org.apache.isis.core.metamodel.facets.members.disabled.DisabledFacet;
+import org.apache.isis.core.metamodel.facets.members.order.MemberOrderFacet;
+import org.apache.isis.core.metamodel.facets.members.order.annotprop.MemberOrderFacetForActionAnnotation;
 import org.apache.isis.core.metamodel.services.ServicesInjector;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.CollectionUtils;
@@ -127,6 +132,7 @@ public class ActionAnnotationFacetFactory extends FacetFactoryAbstract
         processPublishing(processMethodContext);
 
         processTypeOf(processMethodContext);
+        processAssociateWith(processMethodContext);
     }
 
     void processInvocation(final ProcessMethodContext processMethodContext) {
@@ -453,6 +459,53 @@ public class ActionAnnotationFacetFactory extends FacetFactoryAbstract
         FacetUtil.addFacet(typeOfFacet);
     }
 
+    void processAssociateWith(final ProcessMethodContext processMethodContext) {
+
+        final Method method = processMethodContext.getMethod();
+        final FacetedMethod holder = processMethodContext.getFacetHolder();
+
+        // check for @Action(associateWith=...)
+        MemberOrderFacet memberOrderFacet = null;
+
+        final Action action = Annotations.getAnnotation(method, Action.class);
+        if (action != null) {
+            final String associateWith = action.associateWith();
+            final NameAndSequence ns = NameAndSequence.parse(associateWith);
+            if(ns != null) {
+                memberOrderFacet = new MemberOrderFacetForActionAnnotation(ns.name, ns.sequence, holder);
+            }
+        }
+
+        FacetUtil.addFacet(memberOrderFacet);
+    }
+
+    static class NameAndSequence {
+
+        private static final Pattern pattern = Pattern.compile(":");
+        static NameAndSequence parse(final String associateWith) {
+            if(Strings.isNullOrEmpty(associateWith)) {
+                return null;
+            }
+            final String[] split = pattern.split(associateWith);
+            switch (split.length) {
+            case 1:
+                return new NameAndSequence(split[0], "1");
+            case 2:
+                return new NameAndSequence(split[0], split[1]);
+            default:
+                return null;
+            }
+        }
+
+        final String name;
+        final String sequence;
+        NameAndSequence(final String name, final String sequence) {
+            this.name = name;
+            this.sequence = sequence;
+        }
+
+    }
+
     // ///////////////////////////////////////////////////////////////
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/members/order/MemberOrderFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/members/order/MemberOrderFacetAbstract.java
index c888094..edf101d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/members/order/MemberOrderFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/members/order/MemberOrderFacetAbstract.java
@@ -36,26 +36,37 @@ public abstract class MemberOrderFacetAbstract extends MultipleValueFacetAbstrac
     private final String originalName;
     private final String name;
     private final String sequence;
-    private final TranslationService translationService;
 
     public MemberOrderFacetAbstract(
             final String name,
             final String sequence,
             final TranslationService translationService,
             final FacetHolder holder) {
+        this(translatedValueElse(name, "", translationService, holder),
+             sequence,
+             holder);
+    }
+
+    public MemberOrderFacetAbstract(
+            final String name,
+            final String sequence,
+            final FacetHolder holder) {
         super(type(), holder);
-        this.translationService = translationService;
-        this.name = translatedValueElse(name, "");
+        this.name = valueElse(name, "");
         this.originalName = valueElse(name, "");
         this.sequence = valueElse(sequence, "1");
     }
 
-    private String translatedValueElse(final String name, final String defaultValue) {
+    private static String translatedValueElse(
+            final String name,
+            final String defaultValue,
+            final TranslationService translationService,
+            final FacetHolder holder) {
         final boolean nullOrEmpty = Strings.isNullOrEmpty(name);
         if (nullOrEmpty) {
             return defaultValue;
         } else {
-            final IdentifiedHolder identifiedHolder = (IdentifiedHolder) getFacetHolder();
+            final IdentifiedHolder identifiedHolder = (IdentifiedHolder) holder;
             final String context = identifiedHolder.getIdentifier().getClassName();
             return translationService.translate(context, name);
         }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/members/order/annotprop/MemberOrderFacetForActionAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/members/order/annotprop/MemberOrderFacetForActionAnnotation.java
new file mode 100644
index 0000000..0f5dc91
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/members/order/annotprop/MemberOrderFacetForActionAnnotation.java
@@ -0,0 +1,34 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.core.metamodel.facets.members.order.annotprop;
+
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.members.order.MemberOrderFacetAbstract;
+
+public class MemberOrderFacetForActionAnnotation extends MemberOrderFacetAbstract {
+
+    public MemberOrderFacetForActionAnnotation(
+            final String name,
+            final String sequence,
+            final FacetHolder holder) {
+        super(name, sequence, holder);
+    }
+
+}
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest_NameAndSequence_parse.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest_NameAndSequence_parse.java
new file mode 100644
index 0000000..63d0152
--- /dev/null
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest_NameAndSequence_parse.java
@@ -0,0 +1,43 @@
+package org.apache.isis.core.metamodel.facets.actions.action;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class ActionAnnotationFacetFactoryTest_NameAndSequence_parse {
+
+    @Test
+    public void null_or_empty() throws Exception {
+        assertNull(ActionAnnotationFacetFactory.NameAndSequence.parse(null));
+        assertNull(ActionAnnotationFacetFactory.NameAndSequence.parse(""));
+    }
+
+    @Test
+    public void too_long() throws Exception {
+        assertNull(ActionAnnotationFacetFactory.NameAndSequence.parse("abc:def:ghi"));
+    }
+
+    @Test
+    public void name_and_sequence() throws Exception {
+        final ActionAnnotationFacetFactory.NameAndSequence ns =
+                ActionAnnotationFacetFactory.NameAndSequence.parse("items:2.3");
+        assertNotNull(ns);
+
+        assertEquals("items",ns.name);
+        assertEquals("2.3",ns.sequence);
+    }
+
+    @Test
+    public void no_sequence() throws Exception {
+        final ActionAnnotationFacetFactory.NameAndSequence ns =
+                ActionAnnotationFacetFactory.NameAndSequence.parse("items");
+        assertNotNull(ns);
+
+        assertEquals("items",ns.name);
+        assertEquals("1",ns.sequence);
+    }
+
+
+}
\ No newline at end of file
diff --git a/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/dom/impl/SimpleObject.java b/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/dom/impl/SimpleObject.java
index 32ff5bd..9c598d3 100644
--- a/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/dom/impl/SimpleObject.java
+++ b/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/dom/impl/SimpleObject.java
@@ -24,6 +24,7 @@ import javax.jdo.annotations.VersionStrategy;
 import com.google.common.collect.ComparisonChain;
 
 import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.ActionLayout;
 import org.apache.isis.applib.annotation.Auditing;
 import org.apache.isis.applib.annotation.CommandReification;
 import org.apache.isis.applib.annotation.DomainObject;
@@ -63,7 +64,7 @@ public class SimpleObject implements Comparable<SimpleObject> {
     private String notes;
 
 
-    @Action(semantics = SemanticsOf.IDEMPOTENT, command = CommandReification.ENABLED, publishing = Publishing.ENABLED)
+    @Action(semantics = SemanticsOf.IDEMPOTENT, command = CommandReification.ENABLED, publishing = Publishing.ENABLED, associateWith = "name")
     public SimpleObject updateName(
             @Parameter(maxLength = 40)
             @ParameterLayout(named = "Name")
diff --git a/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/dom/impl/SimpleObject.layout.xml b/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/dom/impl/SimpleObject.layout.xml
index 00c97fa..955d478 100644
--- a/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/dom/impl/SimpleObject.layout.xml
+++ b/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/dom/impl/SimpleObject.layout.xml
@@ -34,11 +34,7 @@
                                 <c:action id="delete">
                                     <c:describedAs>Deletes this object from the persistent datastore</c:describedAs>
                                 </c:action>
-                                <c:property id="name" namedEscaped="true">
-                                    <c:action id="updateName">
-                                        <c:describedAs>Updates the object's name</c:describedAs>
-                                    </c:action>
-                                </c:property>
+                                <c:property id="name" namedEscaped="true"/>
                                 <c:property id="notes" namedEscaped="true" multiLine="10" hidden="ALL_TABLES"/>
                             </c:fieldSet>
                         </bs3:col>

-- 
To stop receiving notification emails like this one, please contact
danhaywood@apache.org.