/*
* 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.runtimes.dflt.remoting.common.facade.impl;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import org.apache.isis.applib.Identifier;
import org.apache.isis.core.commons.authentication.AuthenticationSession;
import org.apache.isis.core.commons.config.ConfigurationConstants;
import org.apache.isis.core.commons.config.IsisConfiguration;
import org.apache.isis.core.commons.ensure.Assert;
import org.apache.isis.core.commons.exceptions.IsisException;
import org.apache.isis.core.commons.exceptions.UnexpectedCallException;
import org.apache.isis.core.commons.exceptions.UnknownTypeException;
import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.isis.core.metamodel.adapter.ResolveState;
import org.apache.isis.core.metamodel.adapter.oid.Oid;
import org.apache.isis.core.metamodel.adapter.version.Version;
import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacetUtils;
import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
import org.apache.isis.core.metamodel.spec.ActionType;
import org.apache.isis.core.metamodel.spec.ObjectSpecification;
import org.apache.isis.core.metamodel.spec.SpecificationLoader;
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.specimpl.ObjectActionImpl;
import org.apache.isis.core.runtime.authentication.AuthenticationManager;
import org.apache.isis.core.runtime.authentication.AuthenticationRequestPassword;
import org.apache.isis.runtimes.dflt.remoting.common.IsisRemoteException;
import org.apache.isis.runtimes.dflt.remoting.common.client.transaction.ClientTransactionEvent;
import org.apache.isis.runtimes.dflt.remoting.common.data.Data;
import org.apache.isis.runtimes.dflt.remoting.common.data.common.EncodableObjectData;
import org.apache.isis.runtimes.dflt.remoting.common.data.common.IdentityData;
import org.apache.isis.runtimes.dflt.remoting.common.data.common.NullData;
import org.apache.isis.runtimes.dflt.remoting.common.data.common.ObjectData;
import org.apache.isis.runtimes.dflt.remoting.common.data.common.ReferenceData;
import org.apache.isis.runtimes.dflt.remoting.common.data.query.PersistenceQueryData;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.AuthorizationRequestUsability;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.AuthorizationRequestVisibility;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.AuthorizationResponse;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.ClearAssociationRequest;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.ClearAssociationResponse;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.ClearValueRequest;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.ClearValueResponse;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.CloseSessionRequest;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.CloseSessionResponse;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.ExecuteClientActionRequest;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.ExecuteClientActionResponse;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.ExecuteServerActionRequest;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.ExecuteServerActionResponse;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.FindInstancesRequest;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.FindInstancesResponse;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.GetObjectRequest;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.GetObjectResponse;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.GetPropertiesRequest;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.GetPropertiesResponse;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.HasInstancesRequest;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.HasInstancesResponse;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.KnownObjectsRequest;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.OidForServiceRequest;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.OidForServiceResponse;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.OpenSessionRequest;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.OpenSessionResponse;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.ResolveFieldRequest;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.ResolveFieldResponse;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.ResolveObjectRequest;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.ResolveObjectResponse;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.SetAssociationRequest;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.SetAssociationResponse;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.SetValueRequest;
import org.apache.isis.runtimes.dflt.remoting.common.exchange.SetValueResponse;
import org.apache.isis.runtimes.dflt.remoting.common.facade.ServerFacade;
import org.apache.isis.runtimes.dflt.remoting.common.protocol.ObjectEncoderDecoder;
import org.apache.isis.runtimes.dflt.runtime.persistence.PersistenceConstants;
import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
import org.apache.isis.runtimes.dflt.runtime.system.persistence.PersistenceQuery;
import org.apache.isis.runtimes.dflt.runtime.system.persistence.PersistenceSession;
import org.apache.isis.runtimes.dflt.runtime.system.transaction.IsisTransactionManager;
import org.apache.isis.runtimes.dflt.runtime.system.transaction.MessageBroker;
import org.apache.isis.runtimes.dflt.runtime.system.transaction.UpdateNotifier;
import org.apache.log4j.Logger;
import com.google.common.collect.Lists;
/**
* previously called <tt>ServerDistribution</tt>.
*/
public class ServerFacadeImpl implements ServerFacade {
private static final Logger LOG = Logger.getLogger(ServerFacadeImpl.class);
private final AuthenticationManager authenticationManager;
private ObjectEncoderDecoder encoderDecoder;
public ServerFacadeImpl(final AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
// //////////////////////////////////////////////////////////////
// init, shutdown
// //////////////////////////////////////////////////////////////
@Override
public void init() {
}
@Override
public void shutdown() {
}
// //////////////////////////////////////////////////////////////
// Authentication
// //////////////////////////////////////////////////////////////
@Override
public OpenSessionResponse openSession(final OpenSessionRequest request2) {
final AuthenticationRequestPassword request =
new AuthenticationRequestPassword(request2.getUsername(), request2.getPassword());
final AuthenticationSession session = authenticationManager.authenticate(request);
return new OpenSessionResponse(session);
}
@Override
public CloseSessionResponse closeSession(final CloseSessionRequest request) {
authenticationManager.closeSession(request.getSession());
return new CloseSessionResponse();
}
// //////////////////////////////////////////////////////////////
// Authorization
// //////////////////////////////////////////////////////////////
@Override
public AuthorizationResponse authorizeVisibility(final AuthorizationRequestVisibility request) {
final ObjectAdapter targetAdapter = encoderDecoder.decode(request.getTarget());
final boolean allowed =
getMember(request.getIdentifier()).isVisible(request.getSession(), targetAdapter).isAllowed();
return encoderDecoder.encodeAuthorizeResponse(allowed);
}
@Override
public AuthorizationResponse authorizeUsability(final AuthorizationRequestUsability request) {
final ObjectAdapter targetAdapter = encoderDecoder.decode(request.getTarget());
final boolean allowed =
getMember(request.getIdentifier()).isUsable(request.getSession(), targetAdapter).isAllowed();
return encoderDecoder.encodeAuthorizeResponse(allowed);
}
private ObjectMember getMember(final String memberName) {
final Identifier id = Identifier.fromIdentityString(memberName);
final ObjectSpecification specification = getSpecificationLoader().loadSpecification(id.getClassName());
if (id.isPropertyOrCollection()) {
return getAssociationElseThrowException(id, specification);
} else {
return getActionElseThrowException(id, specification);
}
}
private ObjectMember getActionElseThrowException(final Identifier id, final ObjectSpecification specification) {
final ObjectMember member =
specification.getObjectAction(ActionType.USER, id.getMemberName(), loadParameterSpecifications(id));
if (member == null) {
throw new IsisException("No user action found for id " + id);
}
return member;
}
private ObjectMember getAssociationElseThrowException(final Identifier id, final ObjectSpecification specification) {
final ObjectMember member = specification.getAssociation(id.getMemberName());
if (member == null) {
throw new IsisException("No property or collection found for id " + id);
}
return member;
}
private static List<ObjectSpecification> loadParameterSpecifications(final Identifier id) {
final List<String> parameters = id.getMemberParameterNames();
final List<ObjectSpecification> specifications = Lists.newArrayList();
for (final String parameter : parameters) {
specifications.add(getSpecificationLoader().loadSpecification(parameter));
}
return specifications;
}
// //////////////////////////////////////////////////////////////
// Misc
// //////////////////////////////////////////////////////////////
@Override
public GetPropertiesResponse getProperties(final GetPropertiesRequest request) {
final Properties properties = new Properties();
properties.put("test-client", "true");
// pass over services
final IsisConfiguration configuration = IsisContext.getConfiguration();
final IsisConfiguration serviceProperties =
configuration.getProperties(ConfigurationConstants.ROOT + "services");
for (final String propertyName : serviceProperties) {
properties.put(propertyName, serviceProperties.getString(propertyName));
}
// pass over OID generator
final String oidGeneratorClass = getPersistenceSession().getOidGenerator().getClass().getName();
if (oidGeneratorClass != null) {
properties.put(PersistenceConstants.OID_GENERATOR_CLASS_NAME, oidGeneratorClass);
}
// TODO load up client-side properties
return new GetPropertiesResponse(properties);
}
// //////////////////////////////////////////////////////////////
// setAssociation, setValue, clearAssociation, clearValue
// //////////////////////////////////////////////////////////////
/**
* Applies to both {@link OneToOneAssociation}s and {@link OneToManyAssociation}s.
*/
@Override
public SetAssociationResponse setAssociation(final SetAssociationRequest request) {
final AuthenticationSession session = request.getSession();
final String fieldIdentifier = request.getFieldIdentifier();
final IdentityData targetData = request.getTarget();
final IdentityData associateData = request.getAssociate();
if (LOG.isDebugEnabled()) {
LOG.debug("request setAssociation " + fieldIdentifier + " on " + targetData + " with " + associateData
+ " for " + session);
}
final ObjectAdapter targetAdapter = getPersistentObjectAdapter(session, targetData);
final ObjectAdapter associate = getPersistentObjectAdapter(session, associateData);
final ObjectAssociation association = targetAdapter.getSpecification().getAssociation(fieldIdentifier);
ensureAssociationModifiableElseThrowException(session, targetAdapter, association);
if (association instanceof OneToOneAssociation) {
((OneToOneAssociation) association).setAssociation(targetAdapter, associate);
} else {
((OneToManyAssociation) association).addElement(targetAdapter, associate);
}
return new SetAssociationResponse(getUpdates());
}
/**
* Applies only for {@link OneToOneAssociation}s.
*/
@Override
public SetValueResponse setValue(final SetValueRequest request) {
final AuthenticationSession session = request.getSession();
final String fieldIdentifier = request.getFieldIdentifier();
final IdentityData targetIdentityData = request.getTarget();
final EncodableObjectData encodeableObjectData = request.getValue();
Assert.assertNotNull(encodeableObjectData);
if (LOG.isDebugEnabled()) {
LOG.debug("request setValue " + fieldIdentifier + " on " + targetIdentityData + " with "
+ encodeableObjectData + " for " + session);
}
final ObjectAdapter targetAdapter = getPersistentObjectAdapter(session, targetIdentityData);
final OneToOneAssociation association =
(OneToOneAssociation) targetAdapter.getSpecification().getAssociation(fieldIdentifier);
ensureAssociationModifiableElseThrowException(session, targetAdapter, association);
final String encodedObject = encodeableObjectData.getEncodedObjectData();
final ObjectSpecification specification = association.getSpecification();
final ObjectAdapter adapter = restoreLeafObject(encodedObject, specification);
association.setAssociation(targetAdapter, adapter);
return new SetValueResponse(getUpdates());
}
/**
* Applies to both {@link OneToOneAssociation}s and {@link OneToManyAssociation}s.
*/
@Override
public ClearAssociationResponse clearAssociation(final ClearAssociationRequest request) {
final AuthenticationSession session = request.getSession();
final String fieldIdentifier = request.getFieldIdentifier();
final IdentityData targetData = request.getTarget();
final IdentityData associateData = request.getAssociate();
if (LOG.isDebugEnabled()) {
LOG.debug("request clearAssociation " + fieldIdentifier + " on " + targetData + " of " + associateData
+ " for " + session);
}
final ObjectAdapter targetAdapter = getPersistentObjectAdapter(session, targetData);
final ObjectAdapter associateAdapter = getPersistentObjectAdapter(session, associateData);
final ObjectSpecification specification = targetAdapter.getSpecification();
final ObjectAssociation association = specification.getAssociation(fieldIdentifier);
if (!association.isVisible(session, targetAdapter).isAllowed()
|| association.isUsable(session, targetAdapter).isVetoed()) {
throw new IsisException("can't modify field as not visible or editable");
}
ensureAssociationModifiableElseThrowException(session, targetAdapter, association);
if (association instanceof OneToOneAssociation) {
((OneToOneAssociation) association).clearAssociation(targetAdapter);
} else {
((OneToManyAssociation) association).removeElement(targetAdapter, associateAdapter);
}
return new ClearAssociationResponse(getUpdates());
}
/**
* Applies only for {@link OneToOneAssociation}s.
*/
@Override
public ClearValueResponse clearValue(final ClearValueRequest request) {
final AuthenticationSession session = request.getSession();
final String fieldIdentifier = request.getFieldIdentifier();
final IdentityData targetIdentityData = request.getTarget();
if (LOG.isDebugEnabled()) {
LOG.debug("request clearValue " + fieldIdentifier + " on " + targetIdentityData + " for " + session);
}
final ObjectAdapter targetAdapter = getPersistentObjectAdapter(session, targetIdentityData);
final OneToOneAssociation association =
(OneToOneAssociation) targetAdapter.getSpecification().getAssociation(fieldIdentifier);
ensureAssociationModifiableElseThrowException(session, targetAdapter, association);
association.clearAssociation(targetAdapter);
return new ClearValueResponse(getUpdates());
}
private void ensureAssociationModifiableElseThrowException(final AuthenticationSession session,
final ObjectAdapter targetAdapter, final ObjectAssociation association) {
if (!association.isVisible(session, targetAdapter).isAllowed()
|| association.isUsable(session, targetAdapter).isVetoed()) {
throw new IsisException("can't modify field as not visible or editable");
}
}
// //////////////////////////////////////////////////////////////
// executeClientAction
// //////////////////////////////////////////////////////////////
@Override
public ExecuteClientActionResponse executeClientAction(final ExecuteClientActionRequest request) {
final AuthenticationSession session = request.getSession();
final ReferenceData[] data = request.getData();
final int[] types = request.getTypes();
if (LOG.isDebugEnabled()) {
LOG.debug("execute client action for " + session);
LOG.debug("start transaction");
}
// although the PersistenceSession will also do xactn mgmt, because we
// are potentially modifying several objects we should explicitly define
// the xactn at this level.
getTransactionManager().startTransaction();
try {
final KnownObjectsRequest knownObjects = new KnownObjectsRequest();
final ObjectAdapter[] persistedObjects = new ObjectAdapter[data.length];
final ObjectAdapter[] disposedObjects = new ObjectAdapter[data.length];
final ObjectAdapter[] changedObjects = new ObjectAdapter[data.length];
for (int i = 0; i < data.length; i++) {
ObjectAdapter object;
switch (types[i]) {
case ClientTransactionEvent.ADD:
object = encoderDecoder.decode(data[i], knownObjects);
persistedObjects[i] = object;
if (object.getOid().isTransient()) { // confirm that the graph has not been made
// persistent earlier in this loop
LOG.debug(" makePersistent " + data[i]);
getPersistenceSession().makePersistent(object);
}
break;
case ClientTransactionEvent.CHANGE:
final ObjectAdapter obj = getPersistentObjectAdapter(data[i]);
obj.checkLock(data[i].getVersion());
object = encoderDecoder.decode(data[i], knownObjects);
LOG.debug(" objectChanged " + data[i]);
getPersistenceSession().objectChanged(object);
changedObjects[i] = object;
break;
case ClientTransactionEvent.DELETE:
final ObjectAdapter inObject = getPersistentObjectAdapter(data[i]);
inObject.checkLock(data[i].getVersion());
LOG.debug(" destroyObject " + data[i] + " for " + session);
disposedObjects[i] = inObject;
getPersistenceSession().destroyObject(inObject);
break;
}
}
if (LOG.isDebugEnabled()) {
LOG.debug(" end transaction");
}
getTransactionManager().endTransaction();
final ReferenceData[] madePersistent = new ReferenceData[data.length];
final Version[] changedVersion = new Version[data.length];
for (int i = 0; i < data.length; i++) {
switch (types[i]) {
case ClientTransactionEvent.ADD:
madePersistent[i] = encoderDecoder.encodeIdentityData(persistedObjects[i]);
break;
case ClientTransactionEvent.CHANGE:
changedVersion[i] = changedObjects[i].getVersion();
break;
}
}
return encoderDecoder.encodeClientActionResult(madePersistent, changedVersion, getUpdates());
} catch (final RuntimeException e) {
LOG.info("abort transaction", e);
getTransactionManager().abortTransaction();
throw e;
}
}
// //////////////////////////////////////////////////////////////
// executeServerAction
// //////////////////////////////////////////////////////////////
@Override
public ExecuteServerActionResponse executeServerAction(final ExecuteServerActionRequest request) {
final AuthenticationSession session = request.getSession();
final ActionType actionType = request.getActionType();
final String actionIdentifier = request.getActionIdentifier();
final ReferenceData targetData = request.getTarget();
final Data[] parameterData = request.getParameters();
if (LOG.isDebugEnabled()) {
LOG.debug("request executeAction " + actionIdentifier + " on " + targetData + " for " + session);
}
final KnownObjectsRequest knownObjects = new KnownObjectsRequest();
final ObjectAdapter targetAdapter = decodeTargetAdapter(session, targetData, knownObjects);
final ObjectAction action = targetAdapter.getSpecification().getObjectAction(actionType, actionIdentifier);
final ObjectAdapter[] parameters = decodeParameters(session, parameterData, knownObjects);
if (action == null) {
throw new IsisRemoteException("Could not find method " + actionIdentifier);
}
final ObjectAdapter resultAdapter = action.execute(targetAdapter, parameters);
ObjectData persistedTargetData;
if (targetData == null) {
persistedTargetData = null;
} else if (targetData instanceof ObjectData) {
persistedTargetData = encoderDecoder.encodeMadePersistentGraph((ObjectData) targetData, targetAdapter);
} else {
persistedTargetData = null;
}
final ObjectData[] persistedParameterData = new ObjectData[parameterData.length];
for (int i = 0; i < persistedParameterData.length; i++) {
if (action.getParameters().get(i).getSpecification().isNotCollection()
&& parameterData[i] instanceof ObjectData) {
persistedParameterData[i] =
encoderDecoder.encodeMadePersistentGraph((ObjectData) parameterData[i], parameters[i]);
}
}
final List<String> messages = getMessageBroker().getMessages();
final List<String> warnings = getMessageBroker().getWarnings();
// TODO for efficiency, need to remove the objects in the results graph from the updates set
return encoderDecoder.encodeServerActionResult(resultAdapter, getUpdates(), getDisposed(), persistedTargetData,
persistedParameterData, messages.toArray(new String[0]), warnings.toArray(new String[0]));
}
private ObjectAdapter decodeTargetAdapter(final AuthenticationSession session, final ReferenceData targetData,
final KnownObjectsRequest knownObjects) {
ObjectAdapter targetAdapter;
if (targetData == null) {
throw new IsisRemoteException("No target specified");
} else if (targetData instanceof IdentityData) {
targetAdapter = getPersistentObjectAdapter(session, (IdentityData) targetData);
} else if (targetData instanceof ObjectData) {
targetAdapter = encoderDecoder.decode(targetData, knownObjects);
} else {
// not expected
throw new IsisException();
}
return targetAdapter;
}
@SuppressWarnings("unused")
private ObjectAction getActionMethod(final String actionType, final String actionIdentifier,
final Data[] parameterData, final ObjectAdapter adapter) {
final List<ObjectSpecification> parameterSpecs = Lists.newArrayList();
for (int i = 0; i < parameterSpecs.size(); i++) {
parameterSpecs.add(getSpecification(parameterData[i].getType()));
}
final ActionType type = ObjectActionImpl.getType(actionType);
final int pos = actionIdentifier.indexOf('#');
final String methodName = actionIdentifier.substring(pos + 1);
if (adapter == null) {
throw new UnexpectedCallException("object not specified");
}
return adapter.getSpecification().getObjectAction(type, methodName, parameterSpecs);
}
private ObjectAdapter[] decodeParameters(final AuthenticationSession session, final Data[] parameterData,
final KnownObjectsRequest knownObjects) {
final ObjectAdapter[] parameters = new ObjectAdapter[parameterData.length];
for (int i = 0; i < parameters.length; i++) {
final Data data = parameterData[i];
if (data instanceof NullData) {
continue;
}
if (data instanceof IdentityData) {
parameters[i] = getPersistentObjectAdapter(session, (IdentityData) data);
} else if (data instanceof ObjectData) {
parameters[i] = encoderDecoder.decode(data, knownObjects);
} else if (data instanceof EncodableObjectData) {
final ObjectSpecification valueSpecification =
getSpecificationLoader().loadSpecification(data.getType());
final String valueData = ((EncodableObjectData) data).getEncodedObjectData();
final ObjectAdapter value = restoreLeafObject(valueData, valueSpecification);
/*
* ObjectAdapter value = IsisContext.getObjectLoader().createValueInstance(valueSpecification);
* value.restoreFromEncodedString(valueData);
*/
parameters[i] = value;
} else {
throw new UnknownTypeException(data);
}
}
return parameters;
}
private ReferenceData[] getDisposed() {
final List<ReferenceData> list = new ArrayList<ReferenceData>();
for (final ObjectAdapter element : getUpdateNotifier().getDisposedObjects()) {
list.add(encoderDecoder.encodeIdentityData(element));
}
return list.toArray(new ReferenceData[list.size()]);
}
// //////////////////////////////////////////////////////////////
// getObject, resolve
// //////////////////////////////////////////////////////////////
@Override
public GetObjectResponse getObject(final GetObjectRequest request) {
final Oid oid = request.getOid();
final String specificationName = request.getSpecificationName();
final ObjectSpecification specification = getSpecification(specificationName);
final ObjectAdapter adapter = getPersistenceSession().loadObject(oid, specification);
return new GetObjectResponse(encoderDecoder.encodeForUpdate(adapter));
}
@Override
public ResolveFieldResponse resolveField(final ResolveFieldRequest request) {
final AuthenticationSession session = request.getSession();
final IdentityData targetData = request.getTarget();
final String fieldIdentifier = request.getFieldIdentifier();
if (LOG.isDebugEnabled()) {
LOG.debug("request resolveField " + targetData + "/" + fieldIdentifier + " for " + session);
}
final ObjectSpecification spec = getSpecification(targetData.getType());
final ObjectAssociation field = spec.getAssociation(fieldIdentifier);
final ObjectAdapter targetAdapter = getPersistenceSession().recreateAdapter(targetData.getOid(), spec);
getPersistenceSession().resolveField(targetAdapter, field);
final Data data = encoderDecoder.encodeForResolveField(targetAdapter, fieldIdentifier);
return new ResolveFieldResponse(data);
}
@Override
public ResolveObjectResponse resolveImmediately(final ResolveObjectRequest request) {
final AuthenticationSession session = request.getSession();
final IdentityData targetData = request.getTarget();
if (LOG.isDebugEnabled()) {
LOG.debug("request resolveImmediately " + targetData + " for " + session);
}
final ObjectSpecification spec = getSpecification(targetData.getType());
final ObjectAdapter object = getPersistenceSession().loadObject(targetData.getOid(), spec);
if (object.getResolveState().canChangeTo(ResolveState.RESOLVING)) {
// this is need when the object store does not load the object fully in the getObject() above
getPersistenceSession().resolveImmediately(object);
}
return new ResolveObjectResponse(encoderDecoder.encodeCompletePersistentGraph(object));
}
// //////////////////////////////////////////////////////////////
// findInstances, hasInstances
// //////////////////////////////////////////////////////////////
@Override
public FindInstancesResponse findInstances(final FindInstancesRequest request) {
final AuthenticationSession session = request.getSession();
final PersistenceQueryData criteriaData = request.getCriteria();
final PersistenceQuery criteria = encoderDecoder.decodePersistenceQuery(criteriaData);
LOG.debug("request findInstances " + criteria + " for " + session);
final ObjectAdapter instances = getPersistenceSession().findInstances(criteria);
final ObjectData[] instancesData = convertToCollectionAdapter(instances);
return new FindInstancesResponse(instancesData);
}
@Override
public HasInstancesResponse hasInstances(final HasInstancesRequest request) {
final AuthenticationSession session = request.getSession();
final String specificationName = request.getSpecificationName();
if (LOG.isDebugEnabled()) {
LOG.debug("request hasInstances of " + specificationName + " for " + session);
}
final boolean hasInstances = getPersistenceSession().hasInstances(getSpecification(specificationName));
return new HasInstancesResponse(hasInstances);
}
private ObjectData[] convertToCollectionAdapter(final ObjectAdapter instances) {
final CollectionFacet facet = CollectionFacetUtils.getCollectionFacetFromSpec(instances);
final ObjectData[] data = new ObjectData[facet.size(instances)];
final Enumeration elements = facet.elements(instances);
int i = 0;
while (elements.hasMoreElements()) {
final ObjectAdapter element = (ObjectAdapter) elements.nextElement();
data[i++] = encoderDecoder.encodeCompletePersistentGraph(element);
}
return data;
}
// //////////////////////////////////////////////////////////////
// oidForService
// //////////////////////////////////////////////////////////////
@Override
public OidForServiceResponse oidForService(final OidForServiceRequest request) {
final String serviceId = request.getServiceId();
final ObjectAdapter serviceAdapter = getPersistenceSession().getService(serviceId);
if (serviceAdapter == null) {
throw new IsisRemoteException("Failed to find service " + serviceId);
}
return new OidForServiceResponse(encoderDecoder.encodeIdentityData(serviceAdapter));
}
// //////////////////////////////////////////////////////////////
// Helpers
// //////////////////////////////////////////////////////////////
private ObjectSpecification getSpecification(final String fullName) {
return getSpecificationLoader().loadSpecification(fullName);
}
private ObjectAdapter getPersistentObjectAdapter(final AuthenticationSession session, final IdentityData object) {
final ObjectAdapter obj = getPersistentObjectAdapter(object);
if (LOG.isDebugEnabled()) {
LOG.debug("get object " + object + " for " + session + " --> " + obj);
}
obj.checkLock(object.getVersion());
return obj;
}
private ObjectAdapter getPersistentObjectAdapter(final ReferenceData object) {
final ObjectSpecification spec = getSpecification(object.getType());
final ObjectAdapter obj = getPersistenceSession().loadObject(object.getOid(), spec);
Assert.assertNotNull(obj);
return obj;
}
private ObjectAdapter restoreLeafObject(final String encodedObject, final ObjectSpecification specification) {
final EncodableFacet encoder = specification.getFacet(EncodableFacet.class);
if (encoder == null) {
throw new IsisException("No encoder for " + specification.getFullIdentifier());
}
final ObjectAdapter object = encoder.fromEncodedString(encodedObject);
return object;
}
private ObjectData[] getUpdates() {
final List<ObjectData> list = new ArrayList<ObjectData>();
for (final ObjectAdapter element : getUpdateNotifier().getChangedObjects()) {
list.add(encoderDecoder.encodeForUpdate(element));
}
return list.toArray(new ObjectData[list.size()]);
}
// //////////////////////////////////////////////////////////////
// Dependencies (injected)
// //////////////////////////////////////////////////////////////
public void setEncoder(final ObjectEncoderDecoder objectEncoder) {
this.encoderDecoder = objectEncoder;
}
// //////////////////////////////////////////////////////////////
// Dependencies (from context)
// //////////////////////////////////////////////////////////////
private static SpecificationLoader getSpecificationLoader() {
return IsisContext.getSpecificationLoader();
}
private static PersistenceSession getPersistenceSession() {
return IsisContext.getPersistenceSession();
}
private static IsisTransactionManager getTransactionManager() {
return getPersistenceSession().getTransactionManager();
}
private static UpdateNotifier getUpdateNotifier() {
return IsisContext.getUpdateNotifier();
}
private static MessageBroker getMessageBroker() {
return IsisContext.getMessageBroker();
}
}