/* * 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 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.events.ActionArgumentEvent; import org.apache.isis.applib.events.ActionInvocationEvent; import org.apache.isis.applib.events.ActionUsabilityEvent; import org.apache.isis.applib.events.ActionVisibilityEvent; import org.apache.isis.applib.events.CollectionAccessEvent; import org.apache.isis.applib.events.CollectionAddToEvent; import org.apache.isis.applib.events.CollectionMethodEvent; import org.apache.isis.applib.events.CollectionRemoveFromEvent; import org.apache.isis.applib.events.CollectionUsabilityEvent; import org.apache.isis.applib.events.CollectionVisibilityEvent; import org.apache.isis.applib.events.InteractionEvent; import org.apache.isis.applib.events.ObjectTitleEvent; import org.apache.isis.applib.events.ObjectValidityEvent; import org.apache.isis.applib.events.PropertyAccessEvent; import org.apache.isis.applib.events.PropertyModifyEvent; import org.apache.isis.applib.events.PropertyUsabilityEvent; import org.apache.isis.applib.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.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 "wrap" 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 // ///////////////////////////////////////////////////////////// @Override public <T> T wrap(final T domainObject) { return wrap(domainObject, ExecutionMode.EXECUTE); } @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 (T)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); } @javax.inject.Inject AuthenticationSessionProvider authenticationSessionProvider; // @javax.inject.Inject // SpecificationLoader specificationLoader; @javax.inject.Inject PersistenceSessionServiceInternal persistenceSessionServiceInternal; @javax.inject.Inject IsisSessionFactory isisSessionFactory; }