All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nakedobjects.plugins.remoting.client.facets.ActionInvocationFacetWrapProxy Maven / Gradle / Ivy

package org.nakedobjects.plugins.remoting.client.facets;

import org.apache.log4j.Logger;
import org.nakedobjects.applib.Identifier;
import org.nakedobjects.metamodel.adapter.NakedObject;
import org.nakedobjects.metamodel.adapter.oid.Oid;
import org.nakedobjects.metamodel.authentication.AuthenticationSession;
import org.nakedobjects.metamodel.commons.exceptions.NakedObjectException;
import org.nakedobjects.metamodel.facets.DecoratingFacet;
import org.nakedobjects.metamodel.facets.actions.executed.ExecutedFacet;
import org.nakedobjects.metamodel.facets.actions.executed.ExecutedFacet.Where;
import org.nakedobjects.metamodel.facets.actions.invoke.ActionInvocationFacet;
import org.nakedobjects.metamodel.facets.actions.invoke.ActionInvocationFacetAbstract;
import org.nakedobjects.metamodel.spec.NakedObjectSpecification;
import org.nakedobjects.metamodel.spec.feature.NakedObjectAction;
import org.nakedobjects.metamodel.spec.feature.NakedObjectActionConstants;
import org.nakedobjects.metamodel.spec.feature.NakedObjectActionParameter;
import org.nakedobjects.metamodel.spec.feature.NakedObjectActionType;
import org.nakedobjects.plugins.remoting.shared.ObjectEncoder;
import org.nakedobjects.plugins.remoting.shared.ServerFacade;
import org.nakedobjects.plugins.remoting.shared.data.Data;
import org.nakedobjects.plugins.remoting.shared.data.KnownObjects;
import org.nakedobjects.plugins.remoting.shared.data.NullData;
import org.nakedobjects.plugins.remoting.shared.data.ObjectData;
import org.nakedobjects.plugins.remoting.shared.data.ReferenceData;
import org.nakedobjects.plugins.remoting.shared.data.ServerActionResultData;
import org.nakedobjects.runtime.context.NakedObjectsContext;
import org.nakedobjects.runtime.persistence.ConcurrencyException;
import org.nakedobjects.runtime.persistence.PersistenceSession;
import org.nakedobjects.runtime.persistence.adaptermanager.AdapterManager;


/**
 * A reflection peer for executing actions remotely, instead of on the local machine. Any calls to
 * execute are passed over the network to the server for invocation. There are two cases where
 * the request is not passed to the server, ie it is executed locally: 1) where the method is static, ie is on
 * the class rather than an instance; 2) if the instance is not persistent; 3) if the method is marked as
 * 'local'. If a method is marked as being 'remote' then static methods and methods on transient objects will
 * be passed to the server.
 * 
 * 

* If any of the objects involved have been changed on the server by another process then a * ConcurrencyException will be passed back to the client and re-thrown. *

*/ public final class ActionInvocationFacetWrapProxy extends ActionInvocationFacetAbstract implements DecoratingFacet { private final static Logger LOG = Logger.getLogger(ActionInvocationFacetWrapProxy.class); private final ServerFacade connection; private final ObjectEncoder encoder; private final ActionInvocationFacet underlyingFacet; private final NakedObjectAction peer; public ActionInvocationFacetWrapProxy( final ActionInvocationFacet underlyingFacet, final ServerFacade connection, final ObjectEncoder encoder, final NakedObjectAction peer) { super(underlyingFacet.getFacetHolder()); this.underlyingFacet = underlyingFacet; this.connection = connection; this.encoder = encoder; this.peer = peer; } public ActionInvocationFacet getDecoratedFacet() { return underlyingFacet; } public NakedObject invoke(final NakedObject target, final NakedObject[] parameters) { if (isToBeExecutedRemotely(target)) { /* * NOTE - only remotely executing actions on objects not collection - due to collections not * having OIDs yet */ return executeRemotely(target, parameters); } else { LOG.debug(debug("execute locally", getIdentifier(), target, parameters)); return underlyingFacet.invoke(target, parameters); } } public NakedObjectSpecification getReturnType() { return underlyingFacet.getReturnType(); } public NakedObjectSpecification getOnType() { return underlyingFacet.getOnType(); } public Identifier getIdentifier() { return peer.getIdentifier(); } private NakedObject executeRemotely(final NakedObject targetAdapter, final NakedObject[] parameters) { final KnownObjects knownObjects = new KnownObjects(); final Data[] parameterObjectData = parameterValues(parameters, knownObjects); LOG.debug(debug("execute remotely", getIdentifier(), targetAdapter, parameters)); final ReferenceData targetReference = targetAdapter == null ? null : encoder.createActionTarget(targetAdapter, knownObjects); ServerActionResultData result; try { // peer.getFacet() final NakedObjectActionType type = NakedObjectActionConstants.USER; final String name = getIdentifier().getClassName() + "#" + getIdentifier().getMemberName(); result = connection.executeServerAction( getAuthenticationSession(), type.getName(), name, targetReference, parameterObjectData); } catch (final ConcurrencyException e) { final Oid source = e.getSource(); if (source == null) { throw e; } else { final NakedObject failedObject = getAdapterManager().getAdapterFor(source); getPersistenceSession().reload(failedObject); LOG.info("concurrency conflict: " + e.getMessage()); throw new ConcurrencyException("Object automatically reloaded: " + failedObject.titleString(), e); } } catch (final NakedObjectException e) { LOG.error("remoting exception", e); throw e; } // must deal with transient-now-persistent objects first if (targetAdapter.isTransient()) { encoder.madePersistent(targetAdapter, result.getPersistedTarget()); } final NakedObjectActionParameter[] parameters2 = peer.getParameters(); for (int i = 0; i < parameters.length; i++) { if (parameters2[i].getSpecification().isObject()) { encoder.madePersistent(parameters[i], result.getPersistedParameters()[i]); } } final Data returned = result.getReturn(); NakedObject returnedObject = returned instanceof NullData ? null : encoder.restore(returned); final ObjectData[] updates = result.getUpdates(); for (int i = 0; i < updates.length; i++) { LOG.debug("update " + updates[i].getOid()); encoder.restore(updates[i]); } final ReferenceData[] disposed = result.getDisposed(); for (int i = 0; i < disposed.length; i++) { final Oid oid = disposed[i].getOid(); LOG.debug("disposed " + oid); final NakedObject adapter = getAdapterManager().getAdapterFor(oid); NakedObjectsContext.getUpdateNotifier().addDisposedObject(adapter); } String[] messages = result.getMessages(); for (int i = 0; i < messages.length; i++) { NakedObjectsContext.getMessageBroker().addMessage(messages[i]); } messages = result.getWarnings(); for (int i = 0; i < messages.length; i++) { NakedObjectsContext.getMessageBroker().addWarning(messages[i]); } return returnedObject; } private boolean isToBeExecutedRemotely(final NakedObject targetAdapter) { final ExecutedFacet facet = peer.getFacet(ExecutedFacet.class); final boolean remoteOverride = facet.value() == Where.REMOTELY; // peer.getTarget() == // NakedObjectAction.REMOTE; final boolean localOverride = facet.value() == Where.LOCALLY; // getTarget() == // NakedObjectAction.LOCAL; if (localOverride) { return false; } if (remoteOverride) { return true; } if (targetAdapter.getSpecification().isService()) { return true; } if (targetAdapter == null) { // for static methods there is no target return false; } final boolean remoteAsPersistent = targetAdapter.isPersistent(); return remoteAsPersistent; } private Data[] parameterValues(final NakedObject[] parameters, final KnownObjects knownObjects) { final NakedObjectSpecification[] parameterTypes = new NakedObjectSpecification[parameters.length]; final NakedObjectActionParameter[] parameters2 = peer.getParameters(); for (int i = 0; i < parameterTypes.length; i++) { parameterTypes[i] = parameters[i].getSpecification(); } return encoder.createParameters(parameterTypes, parameters, knownObjects); } private String debug( final String message, final Identifier identifier, final NakedObject target, final NakedObject[] parameters) { if (LOG.isDebugEnabled()) { final StringBuffer str = new StringBuffer(); str.append(message); str.append(" "); str.append(identifier); str.append(" on "); str.append(target); for (int i = 0; i < parameters.length; i++) { if (i > 0) { str.append(','); } str.append(parameters[i]); } return str.toString(); } else { return ""; } } /////////////////////////////////////////////////////////// // Dependencies (from context) /////////////////////////////////////////////////////////// private static PersistenceSession getPersistenceSession() { return NakedObjectsContext.getPersistenceSession(); } private static AdapterManager getAdapterManager() { return getPersistenceSession().getAdapterManager(); } private static AuthenticationSession getAuthenticationSession() { return NakedObjectsContext.getAuthenticationSession(); } } // Copyright (c) Naked Objects Group Ltd.




© 2015 - 2025 Weber Informatics LLC | Privacy Policy