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 2014/05/11 19:41:53 UTC
[08/16] git commit: ISIS-550: Oscar's work to date on
ActionInvokedEvent
ISIS-550: Oscar's work to date on ActionInvokedEvent
- Refactored ActionInvocationFacetViaMethod (distinguish meaning of null, introduced internalInvoke)
- New PostsActionInvokedEvent annotation class
- New facet interface, abstract class, implementation (latter subclassing ActionInvocationFacetViaMethod).
Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/cfcb2018
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/cfcb2018
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/cfcb2018
Branch: refs/heads/master
Commit: cfcb201838aeda52396563539cee2418d5e20f3c
Parents: fe05886
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Sat May 10 07:05:33 2014 +0100
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Sat May 10 07:05:33 2014 +0100
----------------------------------------------------------------------
.../annotation/PostsActionInvokedEvent.java | 67 +++++++
.../services/eventbus/ActionInvokedEvent.java | 63 ++++++
.../event/PostsActionInvokedEventFacet.java | 32 +++
.../PostsActionInvokedEventFacetAbstract.java | 42 ++++
.../invoke/ActionInvocationFacetViaMethod.java | 45 ++++-
.../PostsActionInvokedEventFacetFactory.java | 196 +++++++++++++++++++
.../PostsActionInvokedEventFacetViaMethod.java | 129 ++++++++++++
.../dflt/ProgrammingModelFacetsJava5.java | 2 +
8 files changed, 570 insertions(+), 6 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/isis/blob/cfcb2018/core/applib/src/main/java/org/apache/isis/applib/annotation/PostsActionInvokedEvent.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/PostsActionInvokedEvent.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/PostsActionInvokedEvent.java
new file mode 100644
index 0000000..6b772e7
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/PostsActionInvokedEvent.java
@@ -0,0 +1,67 @@
+/*
+ * 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.applib.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.isis.applib.services.eventbus.ActionInvokedEvent;
+import org.apache.isis.applib.services.eventbus.PropertyChangedEvent;
+import org.apache.isis.applib.services.wrapper.WrapperFactory;
+
+/**
+ * Applies only to actions; any changes should be propagated as events to subscribers.
+ * Only posted if no exception is thrown.
+ *
+ * <p>For example:
+ * <pre>
+ * public static class ChangeStartDateEvent extends ActionInvokedEvent {}
+ *
+ * @PostsActionInvokedEvent(StartDateChangedEvent.class)
+ * public void changeStartDate(final Date startDate) { ...}
+ * </pre>
+ *
+ * <p>
+ * It is highly advisable that only domain services - not domain entities - are registered as subscribers.
+ * Domain services are guaranteed to be instantiated and resident in memory, whereas the same is not true
+ * of domain entities. The typical implementation of a domain service subscriber is to identify the impacted entities,
+ * load them using a repository, and then to delegate to the event to them.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface PostsActionInvokedEvent {
+
+ /**
+ * The subclass of {@link PropertyChangedEvent event} to be instantiated and posted.
+ *
+ * <p>
+ * This subclass must provide a no-arg constructor; the fields are set reflectively.
+ */
+ Class<? extends ActionInvokedEvent<?>> value() default ActionInvokedEvent.Default.class;
+
+ /**
+ * If invoked through the {@link WrapperFactory}, whether business rules ("see it, use it, do it")
+ * should be enforced or not.
+ */
+ WrapperPolicy wrapperPolicy() default WrapperPolicy.ENFORCE_RULES;
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/cfcb2018/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/ActionInvokedEvent.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/ActionInvokedEvent.java b/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/ActionInvokedEvent.java
new file mode 100644
index 0000000..2140525
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/ActionInvokedEvent.java
@@ -0,0 +1,63 @@
+/*
+ * 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.applib.services.eventbus;
+
+import org.apache.isis.applib.annotation.PostsPropertyChangedEvent;
+import org.apache.isis.applib.util.ObjectContracts;
+
+public abstract class ActionInvokedEvent<S> {
+
+ public static class Default extends ActionInvokedEvent<Object> {}
+
+ private final S source;
+ private final String action;
+ private final String parameters;
+
+ /**
+ * To instantiate reflectively when the {@link PostsActionInvokedEvent} annotation
+ * is used.
+ *
+ * <p>
+ * The fields ({@link #source} and {@link #value} are then set reflectively.
+ */
+ public ActionInvokedEvent() {
+ this(null, null, null);
+ }
+
+ public ActionInvokedEvent(S source, String action, String parameters) {
+ this.source = source;
+ this.action = action;
+ this.parameters = parameters;
+ }
+
+ public S getSource() {
+ return source;
+ }
+ public String getAction() {
+ return action;
+ }
+ public String getParameters() {
+ return parameters;
+ }
+
+ @Override
+ public String toString() {
+ return ObjectContracts.toString(this, "source,action,parameters");
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/isis/blob/cfcb2018/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/invoke/event/PostsActionInvokedEventFacet.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/invoke/event/PostsActionInvokedEventFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/invoke/event/PostsActionInvokedEventFacet.java
new file mode 100644
index 0000000..8f9d070
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/invoke/event/PostsActionInvokedEventFacet.java
@@ -0,0 +1,32 @@
+/*
+ * 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.actions.invoke.event;
+
+import org.apache.isis.core.metamodel.facets.actions.invoke.ActionInvocationFacet;
+
+/**
+ * Extends the mechanism by which the action should be invoked by sending an
+ * Event to the internal Event Bus after being invoked without throwing
+ * an Exception.
+ *
+ */
+public interface PostsActionInvokedEventFacet extends ActionInvocationFacet {
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/cfcb2018/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/invoke/event/PostsActionInvokedEventFacetAbstract.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/invoke/event/PostsActionInvokedEventFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/invoke/event/PostsActionInvokedEventFacetAbstract.java
new file mode 100644
index 0000000..8a0115f
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/invoke/event/PostsActionInvokedEventFacetAbstract.java
@@ -0,0 +1,42 @@
+/*
+ * 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.actions.invoke.event;
+
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.FacetAbstract;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.actions.invoke.ActionInvocationFacet;
+
+public abstract class PostsActionInvokedEventFacetAbstract extends FacetAbstract implements ActionInvocationFacet {
+
+ public static Class<? extends Facet> type() {
+
+ // the "primary" type is ActionInvocationFacet rather than PostsActionInvokedEventFacet
+ // so that this facet can wrap an existing (via setUnderlying).
+
+ //return PostsActionInvokedEventFacetAbstract.class;
+ return ActionInvocationFacet.class;
+ }
+
+ public PostsActionInvokedEventFacetAbstract(final FacetHolder holder) {
+ super(type(), holder, Derivation.NOT_DERIVED);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/cfcb2018/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/ActionInvocationFacetViaMethod.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/ActionInvocationFacetViaMethod.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/ActionInvocationFacetViaMethod.java
index 4063b49..c8f81d3 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/ActionInvocationFacetViaMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/ActionInvocationFacetViaMethod.java
@@ -113,13 +113,44 @@ public class ActionInvocationFacetViaMethod extends ActionInvocationFacetAbstrac
public ObjectAdapter invoke(final ObjectAdapter target, final ObjectAdapter[] parameters) {
return invoke(null, target, parameters);
}
-
+
@Override
public ObjectAdapter invoke(
final ObjectAction owningAction,
final ObjectAdapter targetAdapter,
final ObjectAdapter[] arguments) {
-
+
+ // Can return null both because the action finally was not invoked
+ // or because it returned null.
+ return internalInvoke(owningAction, targetAdapter, arguments).getResult();
+
+ }
+
+ public class InvocationResult {
+
+ private final Boolean wasInvoked;
+ private final ObjectAdapter result;
+
+ public InvocationResult(Boolean invoked, ObjectAdapter result) {
+ this.wasInvoked = invoked;
+ this.result = result;
+ }
+
+ public Boolean getWasInvoked() {
+ return wasInvoked;
+ }
+
+ public ObjectAdapter getResult() {
+ return result;
+ }
+
+ }
+
+ protected InvocationResult internalInvoke(
+ final ObjectAction owningAction,
+ final ObjectAdapter targetAdapter,
+ final ObjectAdapter[] arguments) {
+
final Bulk.InteractionContext bulkInteractionContext = getServicesInjector().lookupService(Bulk.InteractionContext.class);
final CommandContext commandContext = getServicesInjector().lookupService(CommandContext.class);
final Command command = commandContext != null ? commandContext.getCommand() : null;
@@ -195,7 +226,7 @@ public class ActionInvocationFacetViaMethod extends ActionInvocationFacetAbstrac
if(commandService.persistIfPossible(command)) {
// force persistence, then return the command itself.
final ObjectAdapter resultAdapter = getAdapterManager().adapterFor(command);
- return resultAdapter;
+ return new InvocationResult(true, resultAdapter);
} else {
throw new IsisException(
"Unable to schedule action '"
@@ -216,7 +247,7 @@ public class ActionInvocationFacetViaMethod extends ActionInvocationFacetAbstrac
LOG.debug(" action result " + result);
}
if (result == null) {
- return null;
+ return new InvocationResult(true, null);
}
final ObjectAdapter resultAdapter = getAdapterManager().adapterFor(result);
@@ -238,7 +269,7 @@ public class ActionInvocationFacetViaMethod extends ActionInvocationFacetAbstrac
? new CurrentInvocation(targetAdapter, getIdentified(), arguments, resultAdapter, command)
:null);
- return resultAdapter;
+ return new InvocationResult(true, resultAdapter);
}
} catch (final IllegalArgumentException e) {
@@ -259,7 +290,9 @@ public class ActionInvocationFacetViaMethod extends ActionInvocationFacetAbstrac
}
ThrowableExtensions.throwWithinIsisException(e, "Exception executing " + method);
- return null;
+
+ // Action was not invoked (an Exception was thrown)
+ return new InvocationResult(false, null);
} catch (final IllegalAccessException e) {
throw new ReflectiveActionException("Illegal access of " + method, e);
}
http://git-wip-us.apache.org/repos/asf/isis/blob/cfcb2018/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/event/PostsActionInvokedEventFacetFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/event/PostsActionInvokedEventFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/event/PostsActionInvokedEventFacetFactory.java
new file mode 100644
index 0000000..e46e7cc
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/event/PostsActionInvokedEventFacetFactory.java
@@ -0,0 +1,196 @@
+/*
+ * 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.progmodel.facets.actions.invoke.event;
+
+import java.lang.reflect.Method;
+
+import org.apache.isis.applib.annotation.PostsCollectionAddedToEvent;
+import org.apache.isis.applib.services.eventbus.CollectionAddedToEvent;
+import org.apache.isis.core.commons.lang.StringExtensions;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManagerAware;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facetapi.FacetUtil;
+import org.apache.isis.core.metamodel.facetapi.FeatureType;
+import org.apache.isis.core.metamodel.facets.Annotations;
+import org.apache.isis.core.metamodel.facets.actions.debug.DebugFacet;
+import org.apache.isis.core.metamodel.facets.actions.exploration.ExplorationFacet;
+import org.apache.isis.core.metamodel.facets.actions.invoke.ActionInvocationFacet;
+import org.apache.isis.core.metamodel.facets.named.NamedFacet;
+import org.apache.isis.core.metamodel.facets.named.NamedFacetInferred;
+import org.apache.isis.core.metamodel.runtimecontext.RuntimeContext;
+import org.apache.isis.core.metamodel.runtimecontext.RuntimeContextAware;
+import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
+import org.apache.isis.core.metamodel.runtimecontext.ServicesInjectorAware;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.progmodel.facets.MethodPrefixBasedFacetFactoryAbstract;
+import org.apache.isis.core.progmodel.facets.actions.invoke.DebugFacetViaNamingConvention;
+import org.apache.isis.core.progmodel.facets.actions.invoke.ExplorationFacetViaNamingConvention;
+
+/**
+ * Sets up {@link ActionInvocationFacet}, along with a number of supporting
+ * facets that are based on the action's name.
+ *
+ * <p>
+ * The supporting methods are: {@link ExecutedFacet}, {@link ExplorationFacet}
+ * and {@link DebugFacet}. In addition a {@link NamedFacet} is inferred from the
+ * name (taking into account the above well-known prefixes).
+ */
+public class PostsActionInvokedEventFacetFactory extends MethodPrefixBasedFacetFactoryAbstract implements AdapterManagerAware, ServicesInjectorAware, RuntimeContextAware {
+
+ private static final String EXPLORATION_PREFIX = "Exploration";
+ private static final String DEBUG_PREFIX = "Debug";
+
+ private static final String[] PREFIXES = { EXPLORATION_PREFIX, DEBUG_PREFIX };
+
+ private AdapterManager adapterManager;
+ private ServicesInjector servicesInjector;
+ private RuntimeContext runtimeContext;
+
+ /**
+ * Note that the {@link Facet}s registered are the generic ones from
+ * noa-architecture (where they exist)
+ */
+ public PostsActionInvokedEventFacetFactory() {
+ super(FeatureType.ACTIONS_ONLY, OrphanValidation.VALIDATE, PREFIXES);
+ }
+
+ // ///////////////////////////////////////////////////////
+ // Actions
+ // ///////////////////////////////////////////////////////
+
+ @Override
+ public void process(final ProcessMethodContext processMethodContext) {
+
+ // InvocationFacet
+ attachInvocationFacet(processMethodContext);
+
+ // DebugFacet, ExplorationFacet
+ attachDebugFacetIfActionMethodNamePrefixed(processMethodContext);
+ attachExplorationFacetIfActionMethodNamePrefixed(processMethodContext);
+
+ // inferred name
+ // (must be called after the attachinvocationFacet methods)
+ attachNamedFacetInferredFromMethodName(processMethodContext);
+ }
+
+ private void attachInvocationFacet(final ProcessMethodContext processMethodContext) {
+
+ final Method actionMethod = processMethodContext.getMethod();
+
+ try {
+ final PostsCollectionAddedToEvent annotation = Annotations.getAnnotation(actionMethod, PostsCollectionAddedToEvent.class);
+ if(annotation == null) {
+ return;
+ }
+
+ final Class<?> returnType = actionMethod.getReturnType();
+ final ObjectSpecification returnSpec = getSpecificationLoader().loadSpecification(returnType);
+ if (returnSpec == null) {
+ return;
+ }
+
+ final Class<?> cls = processMethodContext.getCls();
+ final ObjectSpecification typeSpec = getSpecificationLoader().loadSpecification(cls);
+ final FacetHolder holder = processMethodContext.getFacetHolder();
+
+ final Class<? extends CollectionAddedToEvent<?,?>> changedEventType = annotation.value();
+
+ FacetUtil.addFacet(new PostsActionInvokedEventFacetViaMethod(actionMethod, typeSpec, returnSpec, holder, getRuntimeContext(), getAdapterManager(), getServicesInjector(), changedEventType));
+ } finally {
+ processMethodContext.removeMethod(actionMethod);
+ }
+ }
+
+ private void attachDebugFacetIfActionMethodNamePrefixed(final ProcessMethodContext processMethodContext) {
+
+ final Method actionMethod = processMethodContext.getMethod();
+ final String capitalizedName = StringExtensions.asCapitalizedName(actionMethod.getName());
+ if (!capitalizedName.startsWith(DEBUG_PREFIX)) {
+ return;
+ }
+ final FacetHolder facetedMethod = processMethodContext.getFacetHolder();
+ FacetUtil.addFacet(new DebugFacetViaNamingConvention(facetedMethod));
+ }
+
+ private void attachExplorationFacetIfActionMethodNamePrefixed(final ProcessMethodContext processMethodContext) {
+
+ final Method actionMethod = processMethodContext.getMethod();
+ final String capitalizedName = StringExtensions.asCapitalizedName(actionMethod.getName());
+ if (!capitalizedName.startsWith(EXPLORATION_PREFIX)) {
+ return;
+ }
+ final FacetHolder facetedMethod = processMethodContext.getFacetHolder();
+ FacetUtil.addFacet(new ExplorationFacetViaNamingConvention(facetedMethod));
+ }
+
+ /**
+ * Must be called after added the debug, exploration etc facets.
+ *
+ * <p>
+ * TODO: remove this hack
+ */
+ private void attachNamedFacetInferredFromMethodName(final ProcessMethodContext processMethodContext) {
+
+ final Method method = processMethodContext.getMethod();
+ final String capitalizedName = StringExtensions.asCapitalizedName(method.getName());
+
+ // this is nasty...
+ String name = capitalizedName;
+ name = StringExtensions.removePrefix(name, DEBUG_PREFIX);
+ name = StringExtensions.removePrefix(name, EXPLORATION_PREFIX);
+ name = StringExtensions.asNaturalName2(name);
+
+ final FacetHolder facetedMethod = processMethodContext.getFacetHolder();
+ FacetUtil.addFacet(new NamedFacetInferred(name, facetedMethod));
+ }
+
+ // ///////////////////////////////////////////////////////////////
+ // Dependencies
+ // ///////////////////////////////////////////////////////////////
+
+ @Override
+ public void setAdapterManager(final AdapterManager adapterManager) {
+ this.adapterManager = adapterManager;
+ }
+
+ private AdapterManager getAdapterManager() {
+ return adapterManager;
+ }
+
+ @Override
+ public void setServicesInjector(final ServicesInjector servicesInjector) {
+ this.servicesInjector = servicesInjector;
+ }
+
+ private ServicesInjector getServicesInjector() {
+ return servicesInjector;
+ }
+
+ private RuntimeContext getRuntimeContext() {
+ return runtimeContext;
+ }
+
+ @Override
+ public void setRuntimeContext(RuntimeContext runtimeContext) {
+ this.runtimeContext = runtimeContext;
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/cfcb2018/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/event/PostsActionInvokedEventFacetViaMethod.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/event/PostsActionInvokedEventFacetViaMethod.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/event/PostsActionInvokedEventFacetViaMethod.java
new file mode 100644
index 0000000..7e22b78
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/event/PostsActionInvokedEventFacetViaMethod.java
@@ -0,0 +1,129 @@
+/*
+ * 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.progmodel.facets.actions.invoke.event;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import org.apache.isis.applib.FatalException;
+import org.apache.isis.applib.services.eventbus.ActionInvokedEvent;
+import org.apache.isis.applib.services.eventbus.CollectionAddedToEvent;
+import org.apache.isis.applib.services.eventbus.EventBusService;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.ImperativeFacet;
+import org.apache.isis.core.metamodel.runtimecontext.RuntimeContext;
+import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.progmodel.facets.actions.invoke.ActionInvocationFacetViaMethod;
+
+public class PostsActionInvokedEventFacetViaMethod extends ActionInvocationFacetViaMethod implements ImperativeFacet {
+
+ private EventBusService eventBusService;
+ private boolean searchedForEventBusService = false;
+ private ServicesInjector servicesInjector;
+ private Class<? extends CollectionAddedToEvent<?, ?>> eventType;
+
+ public PostsActionInvokedEventFacetViaMethod(
+ final Method method,
+ final ObjectSpecification onType,
+ final ObjectSpecification returnType,
+ final FacetHolder holder,
+ final RuntimeContext runtimeContext,
+ final AdapterManager adapterManager,
+ final ServicesInjector servicesInjector,
+ final Class<? extends CollectionAddedToEvent<?, ?>> eventType) {
+ super(method, onType, returnType, holder, runtimeContext, adapterManager, servicesInjector);
+
+ // Also needed here.
+ this.servicesInjector = servicesInjector;
+
+ this.eventType = eventType;
+ }
+
+ @Override
+ public ObjectAdapter invoke(
+ final ObjectAction owningAction,
+ final ObjectAdapter targetAdapter,
+ final ObjectAdapter[] arguments) {
+
+ final InvocationResult invocationResult = this.internalInvoke(owningAction, targetAdapter, arguments);
+
+ // Perhaps the Action was not properly invoked (i.e. an exception was raised).
+ if (invocationResult.getWasInvoked()) {
+ // If invoked, then send the ActionInvokedEvent to the EventBus.
+ postEvent(owningAction, targetAdapter, arguments);
+ }
+
+ return invocationResult.getResult();
+
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ private void postEvent(
+ final ObjectAction owningAction,
+ final ObjectAdapter targetAdapter,
+ final ObjectAdapter[] arguments) {
+
+ final Object source = targetAdapter.getObject();
+ try {
+ final Class type = eventType;
+ final ActionInvokedEvent event = newEvent(type, owningAction, source, arguments);
+ getEventBusService().post(event);
+ } catch (Exception e) {
+ throw new FatalException(e);
+ }
+ }
+
+ static <S> ActionInvokedEvent<S> newEvent(
+ final Class<? extends ActionInvokedEvent<S>> type,
+ final ObjectAction owningAction,
+ final S source,
+ final ObjectAdapter[] arguments)
+ throws InstantiationException, IllegalAccessException,
+ NoSuchFieldException {
+ final ActionInvokedEvent<S> event = type.newInstance();
+
+ setField("owningAction", event, owningAction);
+ setField("targetAdapter", event, source);
+ setField("arguments", event, arguments.toString());
+ return event;
+ }
+
+ private static void setField(final String name,
+ final ActionInvokedEvent<?> event, final Object sourceValue)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field sourceField = CollectionAddedToEvent.class
+ .getDeclaredField(name);
+ sourceField.setAccessible(true);
+ sourceField.set(event, sourceValue);
+ }
+
+ private EventBusService getEventBusService() {
+ if (!searchedForEventBusService) {
+ eventBusService = this.servicesInjector.lookupService(EventBusService.class);
+ }
+ searchedForEventBusService = true;
+ return eventBusService;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/cfcb2018/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java b/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
index ca75555..74933a9 100644
--- a/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
+++ b/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
@@ -31,6 +31,7 @@ import org.apache.isis.core.progmodel.facets.actions.defaults.method.ActionDefau
import org.apache.isis.core.progmodel.facets.actions.exploration.annotation.ExplorationAnnotationFacetFactory;
import org.apache.isis.core.progmodel.facets.actions.homepage.HomePageAnnotationFacetFactory;
import org.apache.isis.core.progmodel.facets.actions.invoke.ActionInvocationFacetFactory;
+import org.apache.isis.core.progmodel.facets.actions.invoke.event.PostsActionInvokedEventFacetFactory;
import org.apache.isis.core.progmodel.facets.actions.notcontributed.annotation.NotContributedAnnotationFacetFactory;
import org.apache.isis.core.progmodel.facets.actions.notinservicemenu.annotation.NotInServiceMenuAnnotationFacetFactory;
import org.apache.isis.core.progmodel.facets.actions.notinservicemenu.method.NotInServiceMenuMethodFacetFactory;
@@ -368,6 +369,7 @@ public final class ProgrammingModelFacetsJava5 extends ProgrammingModelAbstract
addFactory(PostsPropertyChangedEventAnnotationFacetFactory.class);
addFactory(PostsCollectionAddedToEventAnnotationFacetFactory.class);
addFactory(PostsCollectionRemovedFromEventAnnotationFacetFactory.class);
+ addFactory(PostsActionInvokedEventFacetFactory.class);
addFactory(ImmutableMarkerInterfaceFacetFactory.class);