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/10/30 17:30:49 UTC

[isis] branch v2 updated (3040c3f -> 3f267b3)

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

danhaywood pushed a change to branch v2
in repository https://gitbox.apache.org/repos/asf/isis.git.


    from 3040c3f  ISIS-1811: when creating CompletableFuture use ForkJoinPool instead of fixed ThreadPool
     add 6765159  Update _dg_ide_intellij.adoc
     add 7796c13  Merge pull request #128 from ppirus/patch-10
     add 39d04f5  ISIS-2025: adds wrapTry for WrapperFactory
     add d8c22ac  ISIS-2027: adds HealthCheckService
     add 41f070c  ISIS-2027: fixes lockdown
     add a3b13aa  ISIS-1899: moves autoCreateAll=true config property from isis-non-changing instead into isis.properties
     new eb7310a  Merge branch 'master' into v2
     add 4c95907  ISIS-2023: backports support of isis.viewer.wicket.themes.initial from v2 to master
     new 3f267b3  Merge branch 'master' into v2

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../guides/rgsvc/_rgsvc_application-layer-spi.adoc |  8 +++
 ...c_application-layer-spi_HealthCheckService.adoc | 53 ++++++++++++++
 ...lication-layer-spi_HomePageProviderService.adoc |  4 +-
 .../main/asciidoc/guides/ugbtb/_ugbtb_web-xml.adoc | 79 ++++++++++++---------
 .../isis/applib/services/health/Health.java}       | 19 +++--
 .../services/health/HealthCheckService.java}       | 13 ++--
 .../applib/services/wrapper/WrapperFactory.java    | 31 +++++++--
 .../commons/authentication/HealthAuthSession.java} | 19 +++--
 .../apache/isis/core/webapp/IsisSessionFilter.java | 22 ++++--
 .../core/webapp/modules/WebModule_RestEasy.java    | 18 ++---
 .../isis/core/wrapper/WrapperFactoryDefault.java   |  5 ++
 .../handlers/DomainObjectInvocationHandler.java    | 63 +++++++++++++++--
 .../IsisSessionFilter_lookupPassThru_Test.java     | 80 ++++++++++++++++++++++
 .../restfulobjects/applib/RepresentationType.java  |  6 +-
 .../restfulobjects/applib/RestfulMediaType.java    |  1 +
 .../HealthRepresentation.java}                     | 11 ++-
 .../HealthResource.java}                           | 18 ++---
 .../server/RestfulObjectsApplication.java          |  2 +
 .../server/resources/HealthReprRenderer.java}      | 43 ++++--------
 ...rverside.java => HealthResourceServerside.java} | 67 +++++++++++-------
 .../application/isis-non-changing.properties       |  1 -
 .../src/main/webapp/WEB-INF/isis.properties        |  5 +-
 .../services/health/HealthCheckServiceImpl.java    | 29 ++++++++
 .../manifest/persistor_datanucleus.properties      |  1 -
 ...ion.services.health.HealthCheckServiceImpl.xml} |  8 +--
 .../modules/simple/dom/impl/SimpleObjects.java     |  8 +++
 .../webapp/src/main/webapp/WEB-INF/isis.properties | 37 +++++-----
 27 files changed, 476 insertions(+), 175 deletions(-)
 create mode 100644 adocs/documentation/src/main/asciidoc/guides/rgsvc/_rgsvc_application-layer-spi_HealthCheckService.adoc
 copy core/{metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/audit/AuditableFacetImpl.java => applib/src/main/java/org/apache/isis/applib/services/health/Health.java} (67%)
 copy core/{metamodel/src/main/java/org/apache/isis/core/metamodel/services/appmanifest/AppManifestProvider.java => applib/src/main/java/org/apache/isis/applib/services/health/HealthCheckService.java} (78%)
 copy core/{runtime/src/main/java/org/apache/isis/core/runtime/system/internal/InitialisationSession.java => metamodel/src/main/java/org/apache/isis/core/commons/authentication/HealthAuthSession.java} (68%)
 create mode 100644 core/runtime/src/test/java/org/apache/isis/core/webapp/IsisSessionFilter_lookupPassThru_Test.java
 copy core/viewer-restfulobjects-applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/{version/VersionRepresentation.java => health/HealthRepresentation.java} (81%)
 copy core/viewer-restfulobjects-applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/{version/VersionResource.java => health/HealthResource.java} (74%)
 copy core/{viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domaintypes/TypeListReprRenderer.java => viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/HealthReprRenderer.java} (50%)
 copy core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/{VersionResourceServerside.java => HealthResourceServerside.java} (51%)
 create mode 100644 example/application/simpleapp/application/src/main/java/domainapp/application/services/health/HealthCheckServiceImpl.java
 copy example/application/simpleapp/application/src/test/java/domainapp/application/integtests/mml/approved/{domainapp.application.fixture.DomainAppFixtureScriptsSpecificationProvider.xml => domainapp.application.services.health.HealthCheckServiceImpl.xml} (87%)


[isis] 01/02: Merge branch 'master' into v2

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit eb7310a04d1d046cf724ae43a544094f9315e96e
Merge: 3040c3f a3b13aa
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Tue Oct 30 09:59:38 2018 +0000

    Merge branch 'master' into v2
    
    ISIS-2027 (health check)
    
    # Conflicts:
    #	core/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrapperFactory.java
    #	example/application/simpleapp/webapp/src/main/webapp/WEB-INF/web.xml

 .../guides/rgsvc/_rgsvc_application-layer-spi.adoc |   8 ++
 ...c_application-layer-spi_HealthCheckService.adoc |  53 +++++++++++
 ...lication-layer-spi_HomePageProviderService.adoc |   4 +-
 .../main/asciidoc/guides/ugbtb/_ugbtb_web-xml.adoc |  79 +++++++++-------
 .../apache/isis/applib/services/health/Health.java |  39 ++++++++
 .../applib/services/health/HealthCheckService.java |  33 +++++++
 .../applib/services/wrapper/WrapperFactory.java    |  31 ++++++-
 .../commons/authentication/HealthAuthSession.java  |  44 +++++++++
 .../apache/isis/core/webapp/IsisSessionFilter.java |  22 ++++-
 .../core/webapp/modules/WebModule_RestEasy.java    |  18 ++--
 .../isis/core/wrapper/WrapperFactoryDefault.java   |   5 +
 .../handlers/DomainObjectInvocationHandler.java    |  63 +++++++++++--
 .../IsisSessionFilter_lookupPassThru_Test.java     |  80 ++++++++++++++++
 .../restfulobjects/applib/RepresentationType.java  |   6 +-
 .../restfulobjects/applib/RestfulMediaType.java    |   1 +
 .../applib/health/HealthRepresentation.java        |  40 ++++++++
 .../applib/health/HealthResource.java              |  44 +++++++++
 .../server/RestfulObjectsApplication.java          |   2 +
 .../server/resources/HealthReprRenderer.java       |  54 +++++++++++
 .../server/resources/HealthResourceServerside.java | 102 +++++++++++++++++++++
 .../application/isis-non-changing.properties       |   1 -
 .../src/main/webapp/WEB-INF/isis.properties        |   5 +-
 .../services/health/HealthCheckServiceImpl.java    |  29 ++++++
 .../manifest/persistor_datanucleus.properties      |   1 -
 ...tion.services.health.HealthCheckServiceImpl.xml |  45 +++++++++
 .../modules/simple/dom/impl/SimpleObjects.java     |   8 ++
 .../webapp/src/main/webapp/WEB-INF/isis.properties |  37 ++++----
 27 files changed, 770 insertions(+), 84 deletions(-)

diff --cc core/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrapperFactory.java
index e38d253,2bd8a21..c7f1b26
--- a/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrapperFactory.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrapperFactory.java
@@@ -112,24 -119,12 +121,29 @@@ public interface WrapperFactory 
              return domainObject;
          }
  
 +        @Override public <T> T w(final T domainObject) {
 +            return wrap(domainObject);
 +        }
 +
 +        @Inject
 +        FactoryService factoryService;
 +
 +        @Override
 +        public <T> T wm(final Class<T> mixinClass, final Object mixedIn) {
 +            return wrapMixin(mixinClass, mixedIn);
 +        }
 +
 +        @Override
 +        public <T> T wrapMixin(final Class<T> mixinClass, final Object mixedIn) {
 +            return wrap(factoryService.m(mixinClass, mixedIn));
 +        }
 +
          @Override
+         public <T> T wrapTry(T domainObject) {
+             return domainObject;
+         }
 -        
++
+         @Override
          public <T> T wrapNoExecute(T domainObject) {
              return domainObject;
          }
@@@ -185,24 -180,13 +199,31 @@@
      <T> T wrap(T domainObject);
  
      /**
 +     * Alias for {@link #wrap(Object)}.
 +     */
 +    @Programmatic
 +    <T> T w(T domainObject);
 +
 +    /**
 +     * Alias for {@link #wrapMixin(Class, Object)}
 +     */
 +    @Programmatic
 +    <T> T wm(Class<T> mixinClass, Object mixedIn);
 +
 +    /**
 +     * {@link #wrap(Object) wraps} a {@link FactoryService#mixin(Class, Object) mixin}.
 +     */
 +    @Programmatic
 +    <T> T wrapMixin(Class<T> mixinClass, Object mixedIn);
 +
 +    /**
+      * Convenience method for {@link #wrap(Object, ExecutionMode)} with {@link ExecutionMode#TRY},
+      * to make this feature more discoverable.
+      */
+     @Programmatic
+     <T> T wrapTry(T domainObject);
+     
+     /**
       * Convenience method for {@link #wrap(Object, ExecutionMode)} with {@link ExecutionMode#NO_EXECUTE},
       * to make this feature more discoverable.
       */
diff --cc core/runtime/src/main/java/org/apache/isis/core/webapp/modules/WebModule_RestEasy.java
index cf22749,0000000..c9465e4
mode 100644,000000..100644
--- a/core/runtime/src/main/java/org/apache/isis/core/webapp/modules/WebModule_RestEasy.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/webapp/modules/WebModule_RestEasy.java
@@@ -1,163 -1,0 +1,163 @@@
 +/*
 + *  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.webapp.modules;
 +
- import static java.util.Objects.requireNonNull;
- import static org.apache.isis.commons.internal.base._Casts.uncheckedCast;
- import static org.apache.isis.commons.internal.base._Strings.prefix;
- import static org.apache.isis.commons.internal.base._Strings.suffix;
- import static org.apache.isis.commons.internal.context._Context.getDefaultClassLoader;
- import static org.apache.isis.commons.internal.exceptions._Exceptions.unexpectedCodeReach;
- import static org.apache.isis.commons.internal.resources._Resources.putRestfulPath;
- 
 +import javax.servlet.FilterRegistration.Dynamic;
 +import javax.servlet.ServletContext;
 +import javax.servlet.ServletContextListener;
 +import javax.servlet.ServletException;
 +
 +import org.apache.isis.core.webapp.IsisSessionFilter;
 +import org.apache.isis.core.webapp.IsisWebAppConfigProvider;
 +
++import static java.util.Objects.requireNonNull;
++import static org.apache.isis.commons.internal.base._Casts.uncheckedCast;
++import static org.apache.isis.commons.internal.base._Strings.prefix;
++import static org.apache.isis.commons.internal.base._Strings.suffix;
++import static org.apache.isis.commons.internal.context._Context.getDefaultClassLoader;
++import static org.apache.isis.commons.internal.exceptions._Exceptions.unexpectedCodeReach;
++import static org.apache.isis.commons.internal.resources._Resources.putRestfulPath;
++
 +/**
 + * Package private mixin for WebModule implementing WebModule.
 + * 
 + * @since 2.0.0
 + */
 +final class WebModule_RestEasy implements WebModule  {
 +    
 +    public static final String KEY_RESTFUL_BASE_PATH = "isis.viewer.restfulobjects.basePath";
 +    public static final String KEY_RESTFUL_BASE_PATH_DEFAULT = "/restful";
 +    
 +    private final static String RESTEASY_BOOTSTRAPPER = 
 +            "org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap";
 +    
 +    private final static String RESTEASY_DISPATCHER = "RestfulObjectsRestEasyDispatcher";
 +    
 +    String restfulPathConfigValue;
 +    
 +    @Override
 +    public String getName() {
 +        return "RestEasy";
 +    }
 +    
 +    @Override
 +    public void prepare(ServletContext ctx) {
 +        
 +        if(!isApplicable(ctx)) {
 +            return;
 +        }
 +        
 +        // try to fetch restfulPath from config else fallback to default
 +        final String restfulPath = 
 +                IsisWebAppConfigProvider.getInstance()
 +                .peekAtOrDefault(ctx, KEY_RESTFUL_BASE_PATH, KEY_RESTFUL_BASE_PATH_DEFAULT);
 +                
 +        putRestfulPath(restfulPath);
 +        
 +        this.restfulPathConfigValue = restfulPath; // store locally for reuse
 +        
 +        // register this module as a viewer
 +        ContextUtil.registerViewer(ctx, "restfulobjects");
 +        ContextUtil.registerProtectedPath(ctx, suffix(prefix(restfulPath, "/"), "/") + "*" );
 +    }
 +
 +    @Override
 +    public ServletContextListener init(ServletContext ctx) throws ServletException {
 +
 +        // add IsisSessionFilters
 +        
 +        {
 +            final Dynamic filter = ctx.addFilter("IsisSessionFilterForRestfulObjects", IsisSessionFilter.class);
 +
 +            // this is mapped to the entire application; 
 +            // however the IsisSessionFilter will 
 +            // "notice" if the session filter has already been
 +            // executed for the request pipeline, and if so will do nothing
 +            filter.addMappingForServletNames(null, true, RESTEASY_DISPATCHER); 
 +            
 +            filter.setInitParameter(
 +                    "authenticationSessionStrategy", 
 +                    "org.apache.isis.viewer.restfulobjects.server.authentication.AuthenticationSessionStrategyBasicAuth");
 +            filter.setInitParameter(
 +                    "whenNoSession", // what to do if no session was found ...
 +                    "auto"); // ... 401 and a basic authentication challenge if request originates from web browser
 +            filter.setInitParameter(
 +                    "passThru", 
-                     getRestfulPath()+"swagger"); 
++                    String.join(",", getRestfulPath()+"swagger", getRestfulPath()+"health"));
 +            
 +        }
 +        
 +        {
 +            final Dynamic filter = ctx.addFilter("RestfulObjectsRestEasyDispatcher", 
 +                    "org.apache.isis.viewer.restfulobjects.server.webapp.IsisTransactionFilterForRestfulObjects");
 +            filter.addMappingForServletNames(null, true, RESTEASY_DISPATCHER); 
 +        }
 +        
 +        
 +
 +        // add RestEasy
 +        
 +        // used by RestEasy to determine the JAX-RS resources and other related configuration
 +        ctx.setInitParameter(
 +                "javax.ws.rs.Application", 
 +                "org.apache.isis.viewer.restfulobjects.server.RestfulObjectsApplication");
 +        
 +        ctx.setInitParameter("resteasy.servlet.mapping.prefix", getRestfulPath());
 +        
 +        ctx.addServlet(RESTEASY_DISPATCHER, 
 +                "org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher");
 +        ctx.getServletRegistration(RESTEASY_DISPATCHER)
 +        .addMapping(getUrlPattern());
 +        
 +        try {
 +            final Class<?> listenerClass = getDefaultClassLoader().loadClass(RESTEASY_BOOTSTRAPPER);
 +            return ctx.createListener(uncheckedCast(listenerClass));
 +        } catch (ClassNotFoundException e) {
 +            // guarded against by isAvailable()
 +            throw unexpectedCodeReach();
 +        }
 +
 +    }
 +
 +    @Override
 +    public boolean isApplicable(ServletContext ctx) {
 +        try {
 +            getDefaultClassLoader().loadClass(RESTEASY_BOOTSTRAPPER);
 +            return true;
 +        } catch (Exception e) {
 +            return false;
 +        }
 +    }
 +    
 +    // -- HELPER
 +    
 +    private String getUrlPattern() {
 +        return getRestfulPath() + "*";
 +    }
 +
 +    private String getRestfulPath() {
 +        requireNonNull(restfulPathConfigValue, "This web-module needs to be prepared first.");
 +        final String restfulPathEnclosedWithSlashes = suffix(prefix(restfulPathConfigValue, "/"), "/");
 +        return restfulPathEnclosedWithSlashes;
 +    }
 +    
 +    
 +
 +    
 +}
diff --cc core/runtime/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryDefault.java
index b56e470,0000000..75e15d2
mode 100644,000000..100644
--- a/core/runtime/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryDefault.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/wrapper/WrapperFactoryDefault.java
@@@ -1,333 -1,0 +1,338 @@@
 +/*
 + *  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.wrapper;
 +
 +
 +import java.util.ArrayList;
 +import java.util.HashMap;
 +import java.util.List;
 +import java.util.Map;
 +
 +import javax.inject.Inject;
 +
 +import org.apache.isis.applib.annotation.DomainService;
 +import org.apache.isis.applib.annotation.NatureOfService;
 +import org.apache.isis.applib.annotation.Programmatic;
 +import org.apache.isis.applib.services.factory.FactoryService;
 +import org.apache.isis.applib.services.wrapper.events.ActionArgumentEvent;
 +import org.apache.isis.applib.services.wrapper.events.ActionInvocationEvent;
 +import org.apache.isis.applib.services.wrapper.events.ActionUsabilityEvent;
 +import org.apache.isis.applib.services.wrapper.events.ActionVisibilityEvent;
 +import org.apache.isis.applib.services.wrapper.events.CollectionAccessEvent;
 +import org.apache.isis.applib.services.wrapper.events.CollectionAddToEvent;
 +import org.apache.isis.applib.services.wrapper.events.CollectionMethodEvent;
 +import org.apache.isis.applib.services.wrapper.events.CollectionRemoveFromEvent;
 +import org.apache.isis.applib.services.wrapper.events.CollectionUsabilityEvent;
 +import org.apache.isis.applib.services.wrapper.events.CollectionVisibilityEvent;
 +import org.apache.isis.applib.services.wrapper.events.InteractionEvent;
 +import org.apache.isis.applib.services.wrapper.events.ObjectTitleEvent;
 +import org.apache.isis.applib.services.wrapper.events.ObjectValidityEvent;
 +import org.apache.isis.applib.services.wrapper.events.PropertyAccessEvent;
 +import org.apache.isis.applib.services.wrapper.events.PropertyModifyEvent;
 +import org.apache.isis.applib.services.wrapper.events.PropertyUsabilityEvent;
 +import org.apache.isis.applib.services.wrapper.events.PropertyVisibilityEvent;
 +import org.apache.isis.applib.services.wrapper.WrapperFactory;
 +import org.apache.isis.applib.services.wrapper.WrappingObject;
 +import org.apache.isis.applib.services.wrapper.listeners.InteractionListener;
 +import org.apache.isis.commons.internal.base._Casts;
 +import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
 +import org.apache.isis.core.metamodel.services.persistsession.PersistenceSessionServiceInternal;
 +import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
 +import org.apache.isis.core.wrapper.dispatchers.InteractionEventDispatcher;
 +import org.apache.isis.core.wrapper.dispatchers.InteractionEventDispatcherTypeSafe;
 +import org.apache.isis.core.wrapper.handlers.ProxyContextHandler;
 +import org.apache.isis.core.wrapper.proxy.ProxyCreator;
 +
 +/**
 + * This service provides the ability to &quot;wrap&quot; of a domain object such that it can
 + * be interacted with while enforcing the hide/disable/validate rules implies by
 + * the Isis programming model.
 + *
 + * <p>
 + * This implementation has no UI-visible actions and is the supported implementation, so it is annotated with
 + * {@link org.apache.isis.applib.annotation.DomainService}.   This means that by including
 + * <tt>o.a.i.core:isis-core-wrapper</tt> on the classpath, the service is automatically registered; no further
 + * configuration is required.
 + */
 +@DomainService(
 +        nature = NatureOfService.DOMAIN,
 +        menuOrder = "" + Integer.MAX_VALUE
 +        )
 +public class WrapperFactoryDefault implements WrapperFactory {
 +
 +    private final List<InteractionListener> listeners = new ArrayList<InteractionListener>();
 +    private final Map<Class<? extends InteractionEvent>, InteractionEventDispatcher> dispatchersByEventClass = new HashMap<Class<? extends InteractionEvent>, InteractionEventDispatcher>();
 +
 +
 +    private final ProxyContextHandler proxyContextHandler;
 +
 +    public WrapperFactoryDefault() {
 +        this(new ProxyCreator());
 +    }
 +    WrapperFactoryDefault(final ProxyCreator proxyCreator) {
 +
 +        proxyContextHandler = new ProxyContextHandler(proxyCreator);
 +
 +        dispatchersByEventClass.put(ObjectTitleEvent.class, new InteractionEventDispatcherTypeSafe<ObjectTitleEvent>() {
 +            @Override
 +            public void dispatchTypeSafe(final ObjectTitleEvent interactionEvent) {
 +                for (final InteractionListener l : getListeners()) {
 +                    l.objectTitleRead(interactionEvent);
 +                }
 +            }
 +        });
 +        dispatchersByEventClass.put(PropertyVisibilityEvent.class, new InteractionEventDispatcherTypeSafe<PropertyVisibilityEvent>() {
 +            @Override
 +            public void dispatchTypeSafe(final PropertyVisibilityEvent interactionEvent) {
 +                for (final InteractionListener l : getListeners()) {
 +                    l.propertyVisible(interactionEvent);
 +                }
 +            }
 +        });
 +        dispatchersByEventClass.put(PropertyUsabilityEvent.class, new InteractionEventDispatcherTypeSafe<PropertyUsabilityEvent>() {
 +            @Override
 +            public void dispatchTypeSafe(final PropertyUsabilityEvent interactionEvent) {
 +                for (final InteractionListener l : getListeners()) {
 +                    l.propertyUsable(interactionEvent);
 +                }
 +            }
 +        });
 +        dispatchersByEventClass.put(PropertyAccessEvent.class, new InteractionEventDispatcherTypeSafe<PropertyAccessEvent>() {
 +            @Override
 +            public void dispatchTypeSafe(final PropertyAccessEvent interactionEvent) {
 +                for (final InteractionListener l : getListeners()) {
 +                    l.propertyAccessed(interactionEvent);
 +                }
 +            }
 +        });
 +        dispatchersByEventClass.put(PropertyModifyEvent.class, new InteractionEventDispatcherTypeSafe<PropertyModifyEvent>() {
 +            @Override
 +            public void dispatchTypeSafe(final PropertyModifyEvent interactionEvent) {
 +                for (final InteractionListener l : getListeners()) {
 +                    l.propertyModified(interactionEvent);
 +                }
 +            }
 +        });
 +        dispatchersByEventClass.put(CollectionVisibilityEvent.class, new InteractionEventDispatcherTypeSafe<CollectionVisibilityEvent>() {
 +            @Override
 +            public void dispatchTypeSafe(final CollectionVisibilityEvent interactionEvent) {
 +                for (final InteractionListener l : getListeners()) {
 +                    l.collectionVisible(interactionEvent);
 +                }
 +            }
 +        });
 +        dispatchersByEventClass.put(CollectionUsabilityEvent.class, new InteractionEventDispatcherTypeSafe<CollectionUsabilityEvent>() {
 +            @Override
 +            public void dispatchTypeSafe(final CollectionUsabilityEvent interactionEvent) {
 +                for (final InteractionListener l : getListeners()) {
 +                    l.collectionUsable(interactionEvent);
 +                }
 +            }
 +        });
 +        dispatchersByEventClass.put(CollectionAccessEvent.class, new InteractionEventDispatcherTypeSafe<CollectionAccessEvent>() {
 +            @Override
 +            public void dispatchTypeSafe(final CollectionAccessEvent interactionEvent) {
 +                for (final InteractionListener l : getListeners()) {
 +                    l.collectionAccessed(interactionEvent);
 +                }
 +            }
 +        });
 +        dispatchersByEventClass.put(CollectionAddToEvent.class, new InteractionEventDispatcherTypeSafe<CollectionAddToEvent>() {
 +            @Override
 +            public void dispatchTypeSafe(final CollectionAddToEvent interactionEvent) {
 +                for (final InteractionListener l : getListeners()) {
 +                    l.collectionAddedTo(interactionEvent);
 +                }
 +            }
 +        });
 +        dispatchersByEventClass.put(CollectionRemoveFromEvent.class, new InteractionEventDispatcherTypeSafe<CollectionRemoveFromEvent>() {
 +            @Override
 +            public void dispatchTypeSafe(final CollectionRemoveFromEvent interactionEvent) {
 +                for (final InteractionListener l : getListeners()) {
 +                    l.collectionRemovedFrom(interactionEvent);
 +                }
 +            }
 +        });
 +        dispatchersByEventClass.put(ActionVisibilityEvent.class, new InteractionEventDispatcherTypeSafe<ActionVisibilityEvent>() {
 +            @Override
 +            public void dispatchTypeSafe(final ActionVisibilityEvent interactionEvent) {
 +                for (final InteractionListener l : getListeners()) {
 +                    l.actionVisible(interactionEvent);
 +                }
 +            }
 +        });
 +        dispatchersByEventClass.put(ActionUsabilityEvent.class, new InteractionEventDispatcherTypeSafe<ActionUsabilityEvent>() {
 +            @Override
 +            public void dispatchTypeSafe(final ActionUsabilityEvent interactionEvent) {
 +                for (final InteractionListener l : getListeners()) {
 +                    l.actionUsable(interactionEvent);
 +                }
 +            }
 +        });
 +        dispatchersByEventClass.put(ActionArgumentEvent.class, new InteractionEventDispatcherTypeSafe<ActionArgumentEvent>() {
 +            @Override
 +            public void dispatchTypeSafe(final ActionArgumentEvent interactionEvent) {
 +                for (final InteractionListener l : getListeners()) {
 +                    l.actionArgument(interactionEvent);
 +                }
 +            }
 +        });
 +        dispatchersByEventClass.put(ActionInvocationEvent.class, new InteractionEventDispatcherTypeSafe<ActionInvocationEvent>() {
 +            @Override
 +            public void dispatchTypeSafe(final ActionInvocationEvent interactionEvent) {
 +                for (final InteractionListener l : getListeners()) {
 +                    l.actionInvoked(interactionEvent);
 +                }
 +            }
 +        });
 +        dispatchersByEventClass.put(ObjectValidityEvent.class, new InteractionEventDispatcherTypeSafe<ObjectValidityEvent>() {
 +            @Override
 +            public void dispatchTypeSafe(final ObjectValidityEvent interactionEvent) {
 +                for (final InteractionListener l : getListeners()) {
 +                    l.objectPersisted(interactionEvent);
 +                }
 +            }
 +        });
 +        dispatchersByEventClass.put(CollectionMethodEvent.class, new InteractionEventDispatcherTypeSafe<CollectionMethodEvent>() {
 +            @Override
 +            public void dispatchTypeSafe(final CollectionMethodEvent interactionEvent) {
 +                for (final InteractionListener l : getListeners()) {
 +                    l.collectionMethodInvoked(interactionEvent);
 +                }
 +            }
 +        });
 +    }
 +
 +    // /////////////////////////////////////////////////////////////
 +    // wrap and unwrap
 +    // /////////////////////////////////////////////////////////////
 +
 +    public <T> T wm(final Class<T> mixinClass, final Object mixedIn) {
 +        return w(factoryService.m(mixinClass, mixedIn));
 +    }
 +
 +    public <T> T wrapMixin(final Class<T> mixinClass, final Object mixedIn) {
 +        return w(factoryService.m(mixinClass, mixedIn));
 +    }
 +
 +    @Override
 +    public <T> T w(final T domainObject) {
 +        return wrap(domainObject, ExecutionMode.EXECUTE);
 +    }
 +
 +    @Override
 +    public <T> T wrap(final T domainObject) {
 +        return wrap(domainObject, ExecutionMode.EXECUTE);
 +    }
 +
 +    @Override
++    public <T> T wrapTry(final T domainObject) {
++        return wrap(domainObject, ExecutionMode.TRY);
++    }
++
++    @Override
 +    public <T> T wrapNoExecute(final T domainObject) {
 +        return wrap(domainObject, ExecutionMode.NO_EXECUTE);
 +    }
 +
 +    @Override
 +    public <T> T wrapSkipRules(final T domainObject) {
 +        return wrap(domainObject, ExecutionMode.SKIP_RULES);
 +    }
 +
 +    @Override
 +    public <T> T wrap(final T domainObject, final ExecutionMode mode) {
 +        if (domainObject instanceof WrappingObject) {
 +            final WrappingObject wrapperObject = (WrappingObject) domainObject;
 +            final ExecutionMode wrapperMode = wrapperObject.__isis_executionMode();
 +            if(wrapperMode != mode) {
 +                final Object underlyingDomainObject = wrapperObject.__isis_wrapped();
 +                return _Casts.uncheckedCast(createProxy(underlyingDomainObject, mode, isisSessionFactory));
 +            }
 +            return domainObject;
 +        }
 +        return createProxy(domainObject, mode, isisSessionFactory);
 +    }
 +
 +    protected <T> T createProxy(
 +            final T domainObject,
 +            final ExecutionMode mode,
 +            final IsisSessionFactory isisSessionFactory) {
 +        return proxyContextHandler.proxy(domainObject, mode, isisSessionFactory);
 +    }
 +
 +    @Override
 +    public boolean isWrapper(final Object possibleWrappedDomainObject) {
 +        return possibleWrappedDomainObject instanceof WrappingObject;
 +    }
 +
 +    @Override
 +    @SuppressWarnings("unchecked")
 +    @Programmatic
 +    public <T> T unwrap(T possibleWrappedDomainObject) {
 +        if(isWrapper(possibleWrappedDomainObject)) {
 +            final WrappingObject wrappingObject = (WrappingObject) possibleWrappedDomainObject;
 +            return (T) wrappingObject.__isis_wrapped();
 +        }
 +        return possibleWrappedDomainObject;
 +    }
 +
 +    // /////////////////////////////////////////////////////////////
 +    // Listeners
 +    // /////////////////////////////////////////////////////////////
 +
 +    @Override
 +    public List<InteractionListener> getListeners() {
 +        return listeners;
 +    }
 +
 +    @Override
 +    public boolean addInteractionListener(final InteractionListener listener) {
 +        return listeners.add(listener);
 +    }
 +
 +    @Override
 +    public boolean removeInteractionListener(final InteractionListener listener) {
 +        return listeners.remove(listener);
 +    }
 +
 +    @Override
 +    public void notifyListeners(final InteractionEvent interactionEvent) {
 +        final InteractionEventDispatcher dispatcher = dispatchersByEventClass.get(interactionEvent.getClass());
 +        if (dispatcher == null) {
 +            throw new RuntimeException("Unknown InteractionEvent - register into dispatchers map");
 +        }
 +        dispatcher.dispatch(interactionEvent);
 +    }
 +
 +
 +    @Inject
 +    AuthenticationSessionProvider authenticationSessionProvider;
 +
 +    @Inject
 +    PersistenceSessionServiceInternal persistenceSessionServiceInternal;
 +
 +    @Inject
 +    IsisSessionFactory isisSessionFactory;
 +
 +    @Inject
 +    FactoryService factoryService;
 +
 +}
diff --cc core/runtime/src/main/java/org/apache/isis/core/wrapper/handlers/DomainObjectInvocationHandler.java
index 8666ded,0000000..5e6e808
mode 100644,000000..100644
--- a/core/runtime/src/main/java/org/apache/isis/core/wrapper/handlers/DomainObjectInvocationHandler.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/wrapper/handlers/DomainObjectInvocationHandler.java
@@@ -1,848 -1,0 +1,897 @@@
 +/*
 + *  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.wrapper.handlers;
 +
 +import java.lang.reflect.InvocationTargetException;
 +import java.lang.reflect.Method;
 +import java.util.Collection;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Optional;
 +import java.util.Set;
 +import java.util.stream.Stream;
 +
 +import org.apache.isis.commons.internal.collections._Lists;
 +import org.apache.isis.commons.internal.collections._Sets;
 +
 +import org.apache.isis.applib.annotation.Where;
 +import org.apache.isis.applib.services.wrapper.DisabledException;
 +import org.apache.isis.applib.services.wrapper.HiddenException;
 +import org.apache.isis.applib.services.wrapper.InteractionException;
 +import org.apache.isis.applib.services.wrapper.InvalidException;
 +import org.apache.isis.applib.services.wrapper.WrapperFactory.ExecutionMode;
 +import org.apache.isis.applib.services.wrapper.WrappingObject;
 +import org.apache.isis.applib.services.wrapper.events.CollectionAccessEvent;
 +import org.apache.isis.applib.services.wrapper.events.InteractionEvent;
 +import org.apache.isis.applib.services.wrapper.events.ObjectTitleEvent;
 +import org.apache.isis.applib.services.wrapper.events.PropertyAccessEvent;
 +import org.apache.isis.applib.services.wrapper.events.UsabilityEvent;
 +import org.apache.isis.applib.services.wrapper.events.ValidityEvent;
 +import org.apache.isis.applib.services.wrapper.events.VisibilityEvent;
 +import org.apache.isis.commons.internal.base._NullSafe;
 +import org.apache.isis.core.commons.authentication.AuthenticationSession;
 +import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
 +import org.apache.isis.core.metamodel.IsisJdoMetamodelPlugin;
 +import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 +import org.apache.isis.core.metamodel.adapter.ObjectAdapterProvider;
 +import org.apache.isis.core.metamodel.consent.Consent;
 +import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 +import org.apache.isis.core.metamodel.consent.InteractionResult;
 +import org.apache.isis.core.metamodel.facets.ImperativeFacet;
 +import org.apache.isis.core.metamodel.facets.ImperativeFacet.Intent;
 +import org.apache.isis.core.metamodel.facets.object.mixin.MixinFacet;
 +import org.apache.isis.core.metamodel.interactions.ObjectTitleContext;
 +import org.apache.isis.core.metamodel.services.ServicesInjector;
 +import org.apache.isis.core.metamodel.services.persistsession.PersistenceSessionServiceInternal;
 +import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 +import org.apache.isis.core.metamodel.spec.feature.Contributed;
 +import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 +import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
 +import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
 +import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
 +import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 +import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 +import org.apache.isis.core.metamodel.specloader.specimpl.ContributeeMember;
 +import org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionContributee;
 +import org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionMixedIn;
 +import org.apache.isis.core.metamodel.specloader.specimpl.dflt.ObjectSpecificationDefault;
 +import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
 +
 +public class DomainObjectInvocationHandler<T> extends DelegatingInvocationHandlerDefault<T> {
 +
 +    private final AuthenticationSessionProvider authenticationSessionProvider;
 +    private final PersistenceSessionServiceInternal persistenceSessionServiceInternal;
 +
 +    private final ProxyContextHandler proxy;
 +    private final ExecutionMode executionMode;
 +    private final IsisSessionFactory isisSessionFactory;
 +
 +    /**
 +     * The <tt>title()</tt> method; may be <tt>null</tt>.
 +     */
 +    protected Method titleMethod;
 +
 +    /**
 +     * The <tt>__isis_save()</tt> method from {@link WrappingObject#__isis_save()}.
 +     */
 +    protected Method __isis_saveMethod;
 +
 +    /**
 +     * The <tt>__isis_wrapped()</tt> method from {@link WrappingObject#__isis_wrapped()}.
 +     */
 +    protected Method __isis_wrappedMethod;
 +
 +    /**
 +     * The <tt>__isis_executionMode()</tt> method from {@link WrappingObject#__isis_executionMode()}.
 +     */
 +    protected Method __isis_executionMode;
 +
 +    protected final Set<String> jdoMethodsProvidedByEnhancement = _Sets.newHashSet();
 +
 +    public DomainObjectInvocationHandler(
 +            final T delegate,
 +            final ExecutionMode mode,
 +            final ProxyContextHandler proxy,
 +            final IsisSessionFactory isisSessionFactory) {
 +        super(delegate, mode, isisSessionFactory);
 +
 +        this.proxy = proxy;
 +        this.executionMode = mode;
 +        this.isisSessionFactory = isisSessionFactory;
 +
 +        final ServicesInjector servicesInjector = isisSessionFactory.getServicesInjector();
 +
 +        this.authenticationSessionProvider = servicesInjector.getAuthenticationSessionProvider();
 +        //this.specificationLoader = servicesInjector.getSpecificationLoader();
 +        this.persistenceSessionServiceInternal = servicesInjector.getPersistenceSessionServiceInternal();
 +
 +
 +        try {
 +            titleMethod = delegate.getClass().getMethod("title", new Class[]{});
 +        } catch (final NoSuchMethodException e) {
 +            // ignore
 +        }
 +        try {
 +            __isis_saveMethod = WrappingObject.class.getMethod("__isis_save", new Class[]{});
 +            __isis_wrappedMethod = WrappingObject.class.getMethod("__isis_wrapped", new Class[]{});
 +            __isis_executionMode = WrappingObject.class.getMethod("__isis_executionMode", new Class[]{});
 +
 +            _NullSafe.stream(IsisJdoMetamodelPlugin.get().getMethodsProvidedByEnhancement())
 +            .map(Method::getName)
 +            .forEach(jdoMethodsProvidedByEnhancement::add);
 +
 +            // legacy of ...
 +            //            dnPersistableMethods.addAll(
 +            //                    _Lists.newArrayList(
 +            //                            Iterables.transform(
 +            //                                    Arrays.asList(Persistable.class.getDeclaredMethods()),
 +            //                                    new Function<Method, String>() {
 +            //                                        @Override
 +            //                                        public String apply(final Method input) {
 +            //                                            return input.getName();
 +            //                                        }
 +            //                                    })));
 +
 +        } catch (final NoSuchMethodException nsme) {
 +            throw new IllegalStateException(
 +                    "Could not locate reserved declared methods in the WrappingObject and WrappedObject interfaces",
 +                    nsme);
 +        }
 +    }
 +
 +    @Override
 +    public Object invoke(final Object proxyObject, final Method method, final Object[] args) throws Throwable {
 +
 +        if (isObjectMethod(method)) {
 +            return delegate(method, args);
 +        }
 +
 +        if(isJdoMethod(method)) {
 +            return delegate(method, args);
 +        }
 +
 +        if(isInjectMethod(method)) {
 +            return delegate(method, args);
 +        }
 +
 +        final ObjectAdapter targetAdapter = adapterFor(getDelegate());
 +
 +        if (isTitleMethod(method)) {
 +            return handleTitleMethod(targetAdapter);
 +        }
 +
 +
 +        final ObjectSpecification targetNoSpec = targetAdapter.getSpecification();
 +
 +        // save method, through the proxy
 +        if (isSaveMethod(method)) {
 +            return handleSaveMethod(targetAdapter, targetNoSpec);
 +        }
 +
 +        if (isWrappedMethod(method)) {
 +            return getDelegate();
 +        }
 +
 +        if (isExecutionModeMethod(method)) {
 +            return executionMode;
 +        }
 +
 +        final ObjectMember objectMember = locateAndCheckMember(method);
 +        final ContributeeMember contributeeMember = determineIfContributed(args, objectMember);
 +
 +        final String memberName = objectMember.getName();
 +
 +        final Intent intent = ImperativeFacet.Util.getIntent(objectMember, method);
 +        if(intent == Intent.CHECK_IF_HIDDEN || intent == Intent.CHECK_IF_DISABLED) {
 +            throw new UnsupportedOperationException(String.format("Cannot invoke supporting method '%s'", memberName));
 +        }
 +
 +        if (intent == Intent.DEFAULTS || intent == Intent.CHOICES_OR_AUTOCOMPLETE) {
 +            return method.invoke(getDelegate(), args);
 +        }
 +
 +        if (objectMember.isOneToOneAssociation()) {
 +
 +            if (intent == Intent.CHECK_IF_VALID || intent == Intent.MODIFY_PROPERTY_SUPPORTING) {
 +                throw new UnsupportedOperationException(String.format("Cannot invoke supporting method for '%s'; use only property accessor/mutator", memberName));
 +            }
 +
 +            final OneToOneAssociation otoa = (OneToOneAssociation) objectMember;
 +
 +            if (intent == Intent.ACCESSOR) {
 +                return handleGetterMethodOnProperty(targetAdapter, args, otoa);
 +            }
 +
 +            if (intent == Intent.MODIFY_PROPERTY || intent == Intent.INITIALIZATION) {
 +                return handleSetterMethodOnProperty(targetAdapter, args, otoa);
 +            }
 +        }
 +        if (objectMember.isOneToManyAssociation()) {
 +
 +            if (intent == Intent.CHECK_IF_VALID) {
 +                throw new UnsupportedOperationException(String.format("Cannot invoke supporting method '%s'; use only collection accessor/mutator", memberName));
 +            }
 +
 +            final OneToManyAssociation otma = (OneToManyAssociation) objectMember;
 +            if (intent == Intent.ACCESSOR) {
 +                return handleGetterMethodOnCollection(targetAdapter, args, otma, method, memberName);
 +            }
 +            if (intent == Intent.MODIFY_COLLECTION_ADD) {
 +                return handleCollectionAddToMethod(targetAdapter, args, otma);
 +            }
 +            if (intent == Intent.MODIFY_COLLECTION_REMOVE) {
 +                return handleCollectionRemoveFromMethod(targetAdapter, args, otma);
 +            }
 +        }
 +
 +        if (objectMember instanceof ObjectAction) {
 +
 +            if (intent == Intent.CHECK_IF_VALID) {
 +                throw new UnsupportedOperationException(String.format("Cannot invoke supporting method '%s'; use only the 'invoke' method", memberName));
 +            }
 +
 +            final ObjectAction objectAction = (ObjectAction) objectMember;
 +
 +            ObjectAction actualObjectAction;
 +            ObjectAdapter actualTargetAdapter;
 +
 +            final MixinFacet mixinFacet = targetAdapter.getSpecification().getFacet(MixinFacet.class);
 +            if(mixinFacet != null) {
 +
 +                // rather than invoke on a (transient) mixin, instead try to
 +                // figure out the corresponding ObjectActionMixedIn
 +                actualTargetAdapter = mixinFacet.mixedIn(targetAdapter, MixinFacet.Policy.IGNORE_FAILURES);
 +                actualObjectAction = determineMixinAction(actualTargetAdapter, objectAction);
 +
 +                if(actualTargetAdapter == null || actualObjectAction == null) {
 +                    // revert to original behaviour
 +                    actualTargetAdapter = targetAdapter;
 +                    actualObjectAction = objectAction;
 +                }
 +            } else {
 +                actualTargetAdapter = targetAdapter;
 +                actualObjectAction = objectAction;
 +            }
 +
 +            return handleActionMethod(actualTargetAdapter, args, actualObjectAction, contributeeMember);
 +        }
 +
 +        throw new UnsupportedOperationException(String.format("Unknown member type '%s'", objectMember));
 +    }
 +
 +    private static ObjectAction determineMixinAction(
 +            final ObjectAdapter domainObjectAdapter,
 +            final ObjectAction objectAction) {
 +        if(domainObjectAdapter == null) {
 +            return null;
 +        }
 +        final ObjectSpecification specification = domainObjectAdapter.getSpecification();
 +        final Stream<ObjectAction> objectActions = specification.streamObjectActions(Contributed.INCLUDED);
 +        
 +        return objectActions
 +            .filter(action->action instanceof ObjectActionMixedIn)
 +            .map(action->(ObjectActionMixedIn) action)
 +            .filter(mixedInAction->mixedInAction.hasMixinAction(objectAction))
 +            .findFirst()
 +            .orElse(null);
 +        
 +        // throw new RuntimeException("Unable to find the mixed-in action corresponding to " + objectAction.getIdentifier().toFullIdentityString());
 +    }
 +
 +    public InteractionInitiatedBy getInteractionInitiatedBy() {
 +        return getExecutionMode().shouldEnforceRules()? InteractionInitiatedBy.USER: InteractionInitiatedBy.FRAMEWORK;
 +    }
 +
 +    // see if this is a contributed property/collection/action
 +    private ContributeeMember determineIfContributed(
 +            final Object[] args,
 +            final ObjectMember objectMember) {
 +
 +        if (!(objectMember instanceof ObjectAction)) {
 +            return null;
 +        }
 +
 +        final ObjectAction objectAction = (ObjectAction) objectMember;
 +
 +        for (final Object arg : args) {
 +            if (arg == null) {
 +                continue;
 +            }
 +            final ObjectSpecificationDefault objectSpec = getJavaSpecification(arg.getClass());
 +
 +            if (args.length == 1) {
 +                // is this a contributed property/collection?
 +                final Stream<ObjectAssociation> associations =
 +                        objectSpec.streamAssociations(Contributed.INCLUDED);
 +                
 +                
 +                final Optional<ContributeeMember> contributeeMember = associations
 +                .filter(association->association instanceof ContributeeMember)
 +                .map(association->(ContributeeMember) association)
 +                .filter(contributeeMember1->contributeeMember1.isContributedBy(objectAction))
 +                .findAny();
 +                
 +                if(contributeeMember.isPresent()) {
 +                    return contributeeMember.get();
 +                }
 +            }
 +
 +            // is this a contributed action?
 +            {
 +                final Stream<ObjectAction> actions =
 +                        objectSpec.streamObjectActions(Contributed.INCLUDED);
 +                
 +                final Optional<ContributeeMember> contributeeMember = actions
 +                        .filter(action->action instanceof ContributeeMember)
 +                        .map(action->(ContributeeMember) action)
 +                        .filter(contributeeMember1->contributeeMember1.isContributedBy(objectAction))
 +                        .findAny();
 +                
 +                if(contributeeMember.isPresent()) {
 +                    return contributeeMember.get();
 +                }
 +            }
 +            
 +        }
 +
 +        return null;
 +    }
 +
 +    private boolean isJdoMethod(final Method method) {
 +        return methodStartsWith(method, "jdo") || jdoMethodsProvidedByEnhancement.contains(method.getName());
 +    }
 +
 +    private static boolean isInjectMethod(final Method method) {
 +        return methodStartsWith(method, "inject");
 +    }
 +
 +    private static boolean methodStartsWith(final Method method, final String prefix) {
 +        return method.getName().startsWith(prefix);
 +    }
 +
 +    // /////////////////////////////////////////////////////////////////
 +    // title
 +    // /////////////////////////////////////////////////////////////////
 +
 +    private Object handleTitleMethod(final ObjectAdapter targetAdapter)
 +            throws IllegalAccessException, InvocationTargetException {
 +
 +        resolveIfRequired(targetAdapter);
 +
 +        final ObjectSpecification targetNoSpec = targetAdapter.getSpecification();
 +        final ObjectTitleContext titleContext = targetNoSpec.createTitleInteractionContext(getAuthenticationSession(), InteractionInitiatedBy.FRAMEWORK, targetAdapter);
 +        final ObjectTitleEvent titleEvent = titleContext.createInteractionEvent();
 +        notifyListeners(titleEvent);
 +        return titleEvent.getTitle();
 +    }
 +
 +    // /////////////////////////////////////////////////////////////////
 +    // save
 +    // /////////////////////////////////////////////////////////////////
 +
 +    private Object handleSaveMethod(
 +            final ObjectAdapter targetAdapter, final ObjectSpecification targetNoSpec) {
 +
 +        if(getExecutionMode().shouldEnforceRules()) {
 +            final InteractionResult interactionResult =
 +                    targetNoSpec.isValidResult(targetAdapter, getInteractionInitiatedBy());
 +            notifyListenersAndVetoIfRequired(interactionResult);
 +        }
 +
 +        if (getExecutionMode().shouldExecute()) {
 +            if (targetAdapter.isTransient()) {
-                 getPersistenceSessionService().makePersistent(targetAdapter);
++                if(getExecutionMode().shouldFailFast()) {
++                    getPersistenceSessionService().makePersistent(targetAdapter);
++                } else {
++                    try {
++                        getPersistenceSessionService().makePersistent(targetAdapter);
++                    } catch(Exception ignore) {
++                        // ignore
++                    }
++                }
 +            }
 +        }
 +        return null;
 +    }
 +
 +    // /////////////////////////////////////////////////////////////////
 +    // property - access
 +    // /////////////////////////////////////////////////////////////////
 +
 +    private Object handleGetterMethodOnProperty(
 +            final ObjectAdapter targetAdapter,
 +            final Object[] args,
 +            final OneToOneAssociation property) {
 +
 +        if (args.length != 0) {
 +            throw new IllegalArgumentException("Invoking a 'get' should have no arguments");
 +        }
 +
 +        if(getExecutionMode().shouldEnforceRules()) {
 +            checkVisibility(targetAdapter, property);
 +        }
 +
 +        resolveIfRequired(targetAdapter);
 +
 +        final InteractionInitiatedBy interactionInitiatedBy = getInteractionInitiatedBy();
 +        final ObjectAdapter currentReferencedAdapter = property.get(targetAdapter, interactionInitiatedBy);
 +
 +        final Object currentReferencedObj = ObjectAdapter.Util.unwrapPojo(currentReferencedAdapter);
 +
 +        final PropertyAccessEvent ev = new PropertyAccessEvent(getDelegate(), property.getIdentifier(), currentReferencedObj);
 +        notifyListeners(ev);
 +        return currentReferencedObj;
 +    }
 +
 +
 +    // /////////////////////////////////////////////////////////////////
 +    // property - modify
 +    // /////////////////////////////////////////////////////////////////
 +
 +    private Object handleSetterMethodOnProperty(
 +            final ObjectAdapter targetAdapter, final Object[] args,
 +            final OneToOneAssociation property) {
 +        if (args.length != 1) {
 +            throw new IllegalArgumentException("Invoking a setter should only have a single argument");
 +        }
 +
 +        final Object argumentObj = underlying(args[0]);
 +
 +        if(getExecutionMode().shouldEnforceRules()) {
 +            checkVisibility(targetAdapter, property);
 +            checkUsability(targetAdapter, property);
 +        }
 +
 +        final ObjectAdapter argumentAdapter = argumentObj != null ? adapterFor(argumentObj) : null;
 +
 +        resolveIfRequired(targetAdapter);
 +
 +
 +        if(getExecutionMode().shouldEnforceRules()) {
 +            final InteractionResult interactionResult = property.isAssociationValid(targetAdapter, argumentAdapter, getInteractionInitiatedBy()).getInteractionResult();
 +            notifyListenersAndVetoIfRequired(interactionResult);
 +        }
 +
 +        if (getExecutionMode().shouldExecute()) {
-             property.set(targetAdapter, argumentAdapter, getInteractionInitiatedBy());
++            if(getExecutionMode().shouldFailFast()) {
++                property.set(targetAdapter, argumentAdapter, getInteractionInitiatedBy());
++            } else {
++                try {
++                    property.set(targetAdapter, argumentAdapter, getInteractionInitiatedBy());
++                } catch(Exception ignore) {
++                    // ignore
++                }
++            }
++
 +        }
 +
 +        return null;
 +    }
 +
 +
 +    // /////////////////////////////////////////////////////////////////
 +    // collection - access
 +    // /////////////////////////////////////////////////////////////////
 +
 +    private Object handleGetterMethodOnCollection(
 +            final ObjectAdapter targetAdapter,
 +            final Object[] args,
 +            final OneToManyAssociation collection,
 +            final Method method,
 +            final String memberName) {
 +
 +        if (args.length != 0) {
 +            throw new IllegalArgumentException("Invoking a 'get' should have no arguments");
 +        }
 +
 +        if(getExecutionMode().shouldEnforceRules()) {
 +            checkVisibility(targetAdapter, collection);
 +        }
 +
 +        resolveIfRequired(targetAdapter);
 +
 +        final InteractionInitiatedBy interactionInitiatedBy = getInteractionInitiatedBy();
 +        final ObjectAdapter currentReferencedAdapter = collection.get(targetAdapter, interactionInitiatedBy);
 +
 +        final Object currentReferencedObj = ObjectAdapter.Util.unwrapPojo(currentReferencedAdapter);
 +
 +        final CollectionAccessEvent ev = new CollectionAccessEvent(getDelegate(), collection.getIdentifier());
 +
 +        if (currentReferencedObj instanceof Collection) {
 +            final Collection<?> collectionViewObject = lookupWrappingObject(method, memberName,
 +                    (Collection<?>) currentReferencedObj, collection);
 +            notifyListeners(ev);
 +            return collectionViewObject;
 +        } else if (currentReferencedObj instanceof Map) {
 +            final Map<?, ?> mapViewObject = lookupWrappingObject(memberName, (Map<?, ?>) currentReferencedObj,
 +                    collection);
 +            notifyListeners(ev);
 +            return mapViewObject;
 +        }
 +        throw new IllegalArgumentException(String.format("Collection type '%s' not supported by framework", currentReferencedObj.getClass().getName()));
 +    }
 +
 +    private Collection<?> lookupWrappingObject(
 +            final Method method,
 +            final String memberName,
 +            final Collection<?> collectionToLookup,
 +            final OneToManyAssociation otma) {
 +        return collectionToLookup instanceof WrappingObject
 +                ? collectionToLookup
 +                        : proxy.proxy(collectionToLookup, memberName, this, otma);
 +    }
 +
 +    private Map<?, ?> lookupWrappingObject(
 +            final String memberName,
 +            final Map<?, ?> mapToLookup,
 +            final OneToManyAssociation otma) {
 +        return mapToLookup instanceof WrappingObject
 +                ? mapToLookup
 +                        : proxy.proxy(mapToLookup, memberName, this, otma);
 +    }
 +
 +    // /////////////////////////////////////////////////////////////////
 +    // collection - add to
 +    // /////////////////////////////////////////////////////////////////
 +
 +    private Object handleCollectionAddToMethod(
 +            final ObjectAdapter targetAdapter,
 +            final Object[] args,
 +            final OneToManyAssociation otma) {
 +
 +        if (args.length != 1) {
 +            throw new IllegalArgumentException("Invoking a addTo should only have a single argument");
 +        }
 +
 +        if(getExecutionMode().shouldEnforceRules()) {
 +            checkVisibility(targetAdapter, otma);
 +            checkUsability(targetAdapter, otma);
 +        }
 +
 +        resolveIfRequired(targetAdapter);
 +
 +        final Object argumentObj = underlying(args[0]);
 +        if (argumentObj == null) {
 +            throw new IllegalArgumentException("Must provide a non-null object to add");
 +        }
 +        final ObjectAdapter argumentNO = adapterFor(argumentObj);
 +
 +        if(getExecutionMode().shouldEnforceRules()) {
 +            final InteractionResult interactionResult = otma.isValidToAdd(targetAdapter, argumentNO,
 +                    getInteractionInitiatedBy()).getInteractionResult();
 +            notifyListenersAndVetoIfRequired(interactionResult);
 +        }
 +
 +        if (getExecutionMode().shouldExecute()) {
-             otma.addElement(targetAdapter, argumentNO, getInteractionInitiatedBy());
++            if(getExecutionMode().shouldFailFast()) {
++                otma.addElement(targetAdapter, argumentNO, getInteractionInitiatedBy());
++            } else {
++                try {
++                    otma.addElement(targetAdapter, argumentNO, getInteractionInitiatedBy());
++                } catch(Exception ignore) {
++                    // ignore
++                }
++            }
 +        }
 +
 +        return null;
 +    }
 +
 +
 +    // /////////////////////////////////////////////////////////////////
 +    // collection - remove from
 +    // /////////////////////////////////////////////////////////////////
 +
 +    private Object handleCollectionRemoveFromMethod(
 +            final ObjectAdapter targetAdapter,
 +            final Object[] args,
 +            final OneToManyAssociation collection) {
 +        if (args.length != 1) {
 +            throw new IllegalArgumentException("Invoking a removeFrom should only have a single argument");
 +        }
 +
 +        if(getExecutionMode().shouldEnforceRules()) {
 +            checkVisibility(targetAdapter, collection);
 +            checkUsability(targetAdapter, collection);
 +        }
 +
 +
 +        resolveIfRequired(targetAdapter);
 +
 +        final Object argumentObj = underlying(args[0]);
 +        if (argumentObj == null) {
 +            throw new IllegalArgumentException("Must provide a non-null object to remove");
 +        }
 +        final ObjectAdapter argumentAdapter = adapterFor(argumentObj);
 +
 +        if(getExecutionMode().shouldEnforceRules()) {
 +            final InteractionResult interactionResult = collection.isValidToRemove(targetAdapter, argumentAdapter,
 +                    getInteractionInitiatedBy()).getInteractionResult();
 +            notifyListenersAndVetoIfRequired(interactionResult);
 +        }
 +
 +        if (getExecutionMode().shouldExecute()) {
-             collection.removeElement(targetAdapter, argumentAdapter, getInteractionInitiatedBy());
++            if(getExecutionMode().shouldFailFast()) {
++                collection.removeElement(targetAdapter, argumentAdapter, getInteractionInitiatedBy());
++            } else {
++                try {
++                    collection.removeElement(targetAdapter, argumentAdapter, getInteractionInitiatedBy());
++                } catch(Exception ignore) {
++                    // ignore
++                }
++            }
 +        }
 +
 +        return null;
 +    }
 +
 +    // /////////////////////////////////////////////////////////////////
 +    // action
 +    // /////////////////////////////////////////////////////////////////
 +
 +    private Object handleActionMethod(
 +            final ObjectAdapter targetAdapter, final Object[] args,
 +            final ObjectAction objectAction,
 +            final ContributeeMember contributeeMember) {
 +
 +        final ObjectAdapter contributeeAdapter;
 +        final Object[] contributeeArgs;
 +        if(contributeeMember != null) {
 +            final int contributeeParamPosition = contributeeMember.getContributeeParamPosition();
 +            final Object contributee = args[contributeeParamPosition];
 +            contributeeAdapter = adapterFor(contributee);
 +
 +            final List<Object> argCopy = _Lists.of(args);
 +            argCopy.remove(contributeeParamPosition);
 +            contributeeArgs = argCopy.toArray();
 +        } else {
 +            contributeeAdapter = null;
 +            contributeeArgs = null;
 +        }
 +
 +        if(getExecutionMode().shouldEnforceRules()) {
 +            if(contributeeMember != null) {
 +                checkVisibility(contributeeAdapter, contributeeMember);
 +                checkUsability(contributeeAdapter, contributeeMember);
 +            } else {
 +                checkVisibility(targetAdapter, objectAction);
 +                checkUsability(targetAdapter, objectAction);
 +            }
 +        }
 +
 +        final ObjectAdapter[] argAdapters = asObjectAdaptersUnderlying(args);
 +
 +        if(getExecutionMode().shouldEnforceRules()) {
 +            if(contributeeMember != null) {
 +                if(contributeeMember instanceof ObjectActionContributee) {
 +                    final ObjectActionContributee objectActionContributee = (ObjectActionContributee) contributeeMember;
 +                    final ObjectAdapter[] contributeeArgAdapters = asObjectAdaptersUnderlying(contributeeArgs);
 +
 +                    checkValidity(contributeeAdapter, objectActionContributee, contributeeArgAdapters);
 +                }
 +                // nothing to do for contributed properties or collections
 +            } else {
 +                checkValidity(targetAdapter, objectAction, argAdapters);
 +            }
 +        }
 +
 +        if (getExecutionMode().shouldExecute()) {
 +            final InteractionInitiatedBy interactionInitiatedBy = getInteractionInitiatedBy();
 +
 +            final ObjectAdapter mixedInAdapter = null; // if a mixin action, then it will automatically fill in.
 +
-             final ObjectAdapter returnedAdapter = objectAction.execute(
-                     targetAdapter, mixedInAdapter, argAdapters,
-                     interactionInitiatedBy);
++
++            ObjectAdapter returnedAdapter;
++
++            if(getExecutionMode().shouldFailFast()) {
++                returnedAdapter = objectAction.execute(
++                        targetAdapter, mixedInAdapter, argAdapters,
++                        interactionInitiatedBy);
++            } else {
++                try {
++                    returnedAdapter = objectAction.execute(
++                            targetAdapter, mixedInAdapter, argAdapters,
++                            interactionInitiatedBy);
++                } catch(Exception ignore) {
++                    // ignore
++                    returnedAdapter = null;
++                }
++
++            }
++
 +
 +            return ObjectAdapter.Util.unwrapPojo(returnedAdapter);
 +        }
 +
 +        return null;
 +    }
 +
 +    private void checkValidity(final ObjectAdapter targetAdapter, final ObjectAction objectAction, final ObjectAdapter[] argAdapters) {
 +        final InteractionResult interactionResult = objectAction.isProposedArgumentSetValid(targetAdapter, argAdapters,
 +                getInteractionInitiatedBy()).getInteractionResult();
 +        notifyListenersAndVetoIfRequired(interactionResult);
 +    }
 +
 +    private ObjectAdapter[] asObjectAdaptersUnderlying(final Object[] args) {
 +
 +        final ObjectAdapter[] argAdapters = new ObjectAdapter[args.length];
 +        int i = 0;
 +        for (final Object arg : args) {
 +            argAdapters[i++] = adapterFor(underlying(arg));
 +        }
 +
 +        return argAdapters;
 +    }
 +
 +    private ObjectAdapter adapterFor(final Object obj) {
 +        return obj != null ? getObjectAdapterProvider().adapterFor(obj) : null;
 +    }
 +
 +    private Object underlying(final Object arg) {
 +        if (arg instanceof WrappingObject) {
 +            final WrappingObject argViewObject = (WrappingObject) arg;
 +            return argViewObject.__isis_wrapped();
 +        } else {
 +            return arg;
 +        }
 +    }
 +
 +    // /////////////////////////////////////////////////////////////////
 +    // visibility and usability checks (common to all members)
 +    // /////////////////////////////////////////////////////////////////
 +
 +    /**
 +     * REVIEW: ideally should provide some way to allow to caller to indicate the 'where' context.  Having
 +     * a hard-coded value like this is an approximation.
 +     */
 +    private final Where where = Where.ANYWHERE;
 +
 +    private void checkVisibility(
 +            final ObjectAdapter targetObjectAdapter,
 +            final ObjectMember objectMember) {
 +        final Consent visibleConsent = objectMember.isVisible(targetObjectAdapter, getInteractionInitiatedBy(), where);
 +        final InteractionResult interactionResult = visibleConsent.getInteractionResult();
 +        notifyListenersAndVetoIfRequired(interactionResult);
 +    }
 +
 +    private void checkUsability(
 +            final ObjectAdapter targetObjectAdapter,
 +            final ObjectMember objectMember) {
 +        final InteractionResult interactionResult = objectMember.isUsable(targetObjectAdapter,
 +                getInteractionInitiatedBy(), where
 +                ).getInteractionResult();
 +        notifyListenersAndVetoIfRequired(interactionResult);
 +    }
 +
 +    // /////////////////////////////////////////////////////////////////
 +    // notify listeners
 +    // /////////////////////////////////////////////////////////////////
 +
 +    private void notifyListenersAndVetoIfRequired(final InteractionResult interactionResult) {
 +        final InteractionEvent interactionEvent = interactionResult.getInteractionEvent();
 +        notifyListeners(interactionEvent);
 +        if (interactionEvent.isVeto()) {
 +            throw toException(interactionEvent);
 +        }
 +    }
 +
 +    /**
 +     * Wraps a {@link InteractionEvent#isVeto() vetoing}
 +     * {@link InteractionEvent} in a corresponding {@link InteractionException},
 +     * and returns it.
 +     */
 +    private InteractionException toException(final InteractionEvent interactionEvent) {
 +        if (!interactionEvent.isVeto()) {
 +            throw new IllegalArgumentException("Provided interactionEvent must be a veto");
 +        }
 +        if (interactionEvent instanceof ValidityEvent) {
 +            final ValidityEvent validityEvent = (ValidityEvent) interactionEvent;
 +            return new InvalidException(validityEvent);
 +        }
 +        if (interactionEvent instanceof VisibilityEvent) {
 +            final VisibilityEvent visibilityEvent = (VisibilityEvent) interactionEvent;
 +            return new HiddenException(visibilityEvent);
 +        }
 +        if (interactionEvent instanceof UsabilityEvent) {
 +            final UsabilityEvent usabilityEvent = (UsabilityEvent) interactionEvent;
 +            return new DisabledException(usabilityEvent);
 +        }
 +        throw new IllegalArgumentException("Provided interactionEvent must be a VisibilityEvent, UsabilityEvent or a ValidityEvent");
 +    }
 +
 +    // /////////////////////////////////////////////////////////////////
 +    // switching
 +    // /////////////////////////////////////////////////////////////////
 +
 +    private ObjectMember locateAndCheckMember(final Method method) {
 +        final ObjectSpecificationDefault objectSpecificationDefault = getJavaSpecificationOfOwningClass(method);
 +        final ObjectMember member = objectSpecificationDefault.getMember(method);
 +
 +        if (member == null) {
 +            final String methodName = method.getName();
 +            throw new UnsupportedOperationException("Method '" + methodName + "' being invoked does not correspond to any of the object's fields or actions.");
 +        }
 +        return member;
 +    }
 +
 +    protected boolean isTitleMethod(final Method method) {
 +        return method.equals(titleMethod);
 +    }
 +
 +    protected boolean isSaveMethod(final Method method) {
 +        return method.equals(__isis_saveMethod);
 +    }
 +
 +    protected boolean isWrappedMethod(final Method method) {
 +        return method.equals(__isis_wrappedMethod);
 +    }
 +
 +    protected boolean isExecutionModeMethod(final Method method) {
 +        return method.equals(__isis_executionMode);
 +    }
 +
 +    // /////////////////////////////////////////////////////////////////
 +    // Specification lookup
 +    // /////////////////////////////////////////////////////////////////
 +
 +    private ObjectSpecificationDefault getJavaSpecificationOfOwningClass(final Method method) {
 +        return getJavaSpecification(method.getDeclaringClass());
 +    }
 +
 +    private ObjectSpecificationDefault getJavaSpecification(final Class<?> clazz) {
 +        final ObjectSpecification objectSpec = getSpecification(clazz);
 +        if (!(objectSpec instanceof ObjectSpecificationDefault)) {
 +            throw new UnsupportedOperationException("Only Java is supported (specification is '" + objectSpec.getClass().getCanonicalName() + "')");
 +        }
 +        return (ObjectSpecificationDefault) objectSpec;
 +    }
 +
 +    private ObjectSpecification getSpecification(final Class<?> type) {
 +        return getSpecificationLoader().loadSpecification(type);
 +    }
 +
 +    // /////////////////////////////////////////////////////////////////
 +    // Dependencies
 +    // /////////////////////////////////////////////////////////////////
 +
 +    protected SpecificationLoader getSpecificationLoader() {
 +        return isisSessionFactory.getSpecificationLoader();
 +    }
 +
 +    public AuthenticationSessionProvider getAuthenticationSessionProvider() {
 +        return authenticationSessionProvider;
 +    }
 +
 +    protected AuthenticationSession getAuthenticationSession() {
 +        return getAuthenticationSessionProvider().getAuthenticationSession();
 +    }
 +
 +    protected ObjectAdapterProvider getObjectAdapterProvider() {
 +        return persistenceSessionServiceInternal;
 +    }
 +    
 +    protected PersistenceSessionServiceInternal getPersistenceSessionService() {
 +        return persistenceSessionServiceInternal;
 +    }
 +
 +    public IsisSessionFactory getIsisSessionFactory() {
 +        return isisSessionFactory;
 +    }
 +}
diff --cc core/viewer-restfulobjects-applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/RepresentationType.java
index 059630f,70c2794..4075ffe
--- a/core/viewer-restfulobjects-applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/RepresentationType.java
+++ b/core/viewer-restfulobjects-applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/RepresentationType.java
@@@ -18,9 -18,7 +18,8 @@@
   */
  package org.apache.isis.viewer.restfulobjects.applib;
  
- 
  import java.util.Collections;
 +import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
@@@ -41,9 -41,9 +40,10 @@@ import org.apache.isis.viewer.restfulob
  import org.apache.isis.viewer.restfulobjects.applib.domaintypes.TypeActionResultRepresentation;
  import org.apache.isis.viewer.restfulobjects.applib.domaintypes.TypeListRepresentation;
  import org.apache.isis.viewer.restfulobjects.applib.errors.ErrorRepresentation;
+ import org.apache.isis.viewer.restfulobjects.applib.health.HealthRepresentation;
  import org.apache.isis.viewer.restfulobjects.applib.homepage.HomePageRepresentation;
  import org.apache.isis.viewer.restfulobjects.applib.user.UserRepresentation;
 +import org.apache.isis.viewer.restfulobjects.applib.util.MediaTypes;
  import org.apache.isis.viewer.restfulobjects.applib.util.Parser;
  import org.apache.isis.viewer.restfulobjects.applib.version.VersionRepresentation;
  
diff --cc core/viewer-restfulobjects-applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/health/HealthResource.java
index 0000000,c00aeca..f624932
mode 000000,100644..100644
--- a/core/viewer-restfulobjects-applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/health/HealthResource.java
+++ b/core/viewer-restfulobjects-applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/health/HealthResource.java
@@@ -1,0 -1,51 +1,44 @@@
+ /*
+  *  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.viewer.restfulobjects.applib.health;
+ 
 -import javax.ws.rs.DELETE;
 -import javax.ws.rs.GET;
 -import javax.ws.rs.POST;
 -import javax.ws.rs.PUT;
 -import javax.ws.rs.Path;
 -import javax.ws.rs.Produces;
++import javax.ws.rs.*;
+ import javax.ws.rs.core.MediaType;
+ import javax.ws.rs.core.Response;
+ 
 -import org.jboss.resteasy.annotations.ClientResponseType;
 -
+ import org.apache.isis.viewer.restfulobjects.applib.RestfulMediaType;
+ 
+ @Path("/health")
+ public interface HealthResource {
+ 
+     @GET
+     @Produces({ MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_HEALTH })
 -    @ClientResponseType(entityType = String.class)
++    //TODO @ClientResponseType(entityType = String.class)
+     public Response health();
+ 
+     @DELETE
+     public Response deleteHealthNotAllowed();
+ 
+     @PUT
+     public Response putHealthNotAllowed();
+ 
+     @POST
+     public Response postHealthNotAllowed();
+ 
+ }
diff --cc example/application/simpleapp/application/src/test/java/domainapp/application/integtests/mml/approved/domainapp.application.services.health.HealthCheckServiceImpl.xml
index 0000000,a2ed203..b2eaa9d
mode 000000,100644..100644
--- a/example/application/simpleapp/application/src/test/java/domainapp/application/integtests/mml/approved/domainapp.application.services.health.HealthCheckServiceImpl.xml
+++ b/example/application/simpleapp/application/src/test/java/domainapp/application/integtests/mml/approved/domainapp.application.services.health.HealthCheckServiceImpl.xml
@@@ -1,0 -1,50 +1,45 @@@
+ <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+ <mml:domainClassDto id="domainapp.application.services.health.HealthCheckServiceImpl" service="true" xmlns:mml="http://isis.apache.org/schema/metamodel">
+     <mml:facets>
+         <mml:facet id="org.apache.isis.core.metamodel.facets.all.named.NamedFacet" fqcn="org.apache.isis.core.metamodel.facets.all.named.NamedFacetInferred">
+             <mml:attr name="escaped">true</mml:attr>
+             <mml:attr name="value">Health Check Service Impl</mml:attr>
+         </mml:facet>
++        <mml:facet id="org.apache.isis.core.metamodel.facets.object.audit.AuditableFacet" fqcn="org.apache.isis.core.metamodel.facets.object.domainobject.auditing.AuditableFacetFromConfiguration">
++            <mml:attr name="enablement">ENABLED</mml:attr>
++        </mml:facet>
+         <mml:facet id="org.apache.isis.core.metamodel.facets.object.bookmarkpolicy.BookmarkPolicyFacet" fqcn="org.apache.isis.core.metamodel.facets.object.bookmarkpolicy.BookmarkPolicyFacetFallback">
+             <mml:attr name="bookmarkPolicy">NEVER</mml:attr>
+         </mml:facet>
+         <mml:facet id="org.apache.isis.core.metamodel.facets.object.domainservice.DomainServiceFacet" fqcn="org.apache.isis.core.metamodel.facets.object.domainservice.annotation.DomainServiceFacetAnnotation">
+             <mml:attr name="natureOfService">DOMAIN</mml:attr>
+             <mml:attr name="repositoryFor">java.lang.Object</mml:attr>
+         </mml:facet>
+         <mml:facet id="org.apache.isis.core.metamodel.facets.object.domainservicelayout.DomainServiceLayoutFacet" fqcn="org.apache.isis.core.metamodel.facets.object.domainservicelayout.annotation.DomainServiceLayoutFacetAnnotation">
+             <mml:attr name="menuBar">PRIMARY</mml:attr>
 -            <mml:attr name="menuOrder">2147483547</mml:attr>
+         </mml:facet>
+         <mml:facet id="org.apache.isis.core.metamodel.facets.object.grid.GridFacet" fqcn="org.apache.isis.core.metamodel.facets.object.grid.GridFacetDefault"/>
+         <mml:facet id="org.apache.isis.core.metamodel.facets.object.icon.IconFacet" fqcn="org.apache.isis.core.metamodel.facets.object.domainservice.annotation.IconFacetDerivedFromDomainServiceAnnotation">
+             <mml:attr name="repositoryFor">java.lang.Object</mml:attr>
+         </mml:facet>
 -        <mml:facet id="org.apache.isis.core.metamodel.facets.object.membergroups.MemberGroupLayoutFacet" fqcn="org.apache.isis.core.metamodel.facets.object.membergroups.annotprop.MemberGroupLayoutFacetFallback">
 -            <mml:attr name="columns">[4,0,0,8]</mml:attr>
 -            <mml:attr name="left">General</mml:attr>
 -        </mml:facet>
 -        <mml:facet id="org.apache.isis.core.metamodel.facets.object.notpersistable.NotPersistableFacet" fqcn="org.apache.isis.core.metamodel.facets.fallback.NotPersistableFacetNull">
 -            <mml:attr name="disabling">true</mml:attr>
 -        </mml:facet>
+         <mml:facet id="org.apache.isis.core.metamodel.facets.object.objectspecid.ObjectSpecIdFacet" fqcn="org.apache.isis.core.metamodel.facets.object.objectspecid.classname.ObjectSpecIdFacetDerivedFromClassName">
+             <mml:attr name="derived">true</mml:attr>
+             <mml:attr name="value">domainapp.application.services.health.HealthCheckServiceImpl</mml:attr>
+         </mml:facet>
+         <mml:facet id="org.apache.isis.core.metamodel.facets.object.objectvalidprops.ObjectValidPropertiesFacet" fqcn="org.apache.isis.core.metamodel.facets.object.objectvalidprops.impl.ObjectValidPropertiesFacetImpl">
+             <mml:attr name="validating">true</mml:attr>
+         </mml:facet>
+         <mml:facet id="org.apache.isis.core.metamodel.facets.object.paged.PagedFacet" fqcn="org.apache.isis.core.metamodel.facets.fallback.PagedFacetFromConfiguration">
+             <mml:attr name="derived">true</mml:attr>
+             <mml:attr name="value">25</mml:attr>
+         </mml:facet>
+         <mml:facet id="org.apache.isis.core.metamodel.facets.object.plural.PluralFacet" fqcn="org.apache.isis.core.metamodel.facets.object.plural.inferred.PluralFacetInferred">
+             <mml:attr name="derived">true</mml:attr>
+             <mml:attr name="value">Health Check Service Impls</mml:attr>
+         </mml:facet>
+         <mml:facet id="org.apache.isis.core.runtime.authorization.standard.AuthorizationFacet" fqcn="org.apache.isis.core.runtime.authorization.standard.AuthorizationFacetImpl">
+             <mml:attr name="disabling">true</mml:attr>
+             <mml:attr name="hiding">true</mml:attr>
+         </mml:facet>
+     </mml:facets>
+ </mml:domainClassDto>
diff --cc example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/dom/impl/SimpleObjects.java
index d62b3e6,5aa77cf..30771d1
--- a/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/dom/impl/SimpleObjects.java
+++ b/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/dom/impl/SimpleObjects.java
@@@ -82,6 -82,14 +82,14 @@@ public class SimpleObjects 
                  .executeUnique();
      }
  
+     @Programmatic
+     public void ping() {
 -        TypesafeQuery<SimpleObject> q = isisJdoSupport.newTypesafeQuery(SimpleObject.class);
++        JDOQLTypedQuery<SimpleObject> q = isisJdoSupport.newTypesafeQuery(SimpleObject.class);
+         final QSimpleObject candidate = QSimpleObject.candidate();
+         q.range(0,2);
+         q.orderBy(candidate.name.asc());
+         q.executeList();
+     }
  
      public static class CreateDomainEvent extends ActionDomainEvent<SimpleObjects> {}
      @Action(domainEvent = CreateDomainEvent.class)


[isis] 02/02: Merge branch 'master' into v2

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 3f267b3b100bde0bbcc010159e0f6f9e66d1ee70
Merge: eb7310a 4c95907
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Tue Oct 30 17:04:01 2018 +0000

    Merge branch 'master' into v2
    
    # Conflicts:
    #	core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java