org.nakedobjects.nos.remote.command.marshal.Marshaller Maven / Gradle / Ivy
package org.nakedobjects.nos.remote.command.marshal;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import org.nakedobjects.noa.adapter.Naked;
import org.nakedobjects.noa.adapter.NakedCollection;
import org.nakedobjects.noa.adapter.NakedObject;
import org.nakedobjects.noa.adapter.NakedValue;
import org.nakedobjects.noa.adapter.Oid;
import org.nakedobjects.noa.adapter.ResolveState;
import org.nakedobjects.noa.adapter.Version;
import org.nakedobjects.noa.persist.InstancesCriteria;
import org.nakedobjects.noa.reflect.NakedObjectField;
import org.nakedobjects.noa.spec.NakedObjectSpecification;
import org.nakedobjects.nof.core.context.NakedObjectsContext;
import org.nakedobjects.nof.core.util.Assert;
import org.nakedobjects.nof.core.util.UnknownTypeException;
import org.nakedobjects.nof.reflect.remote.NakedObjectsRemoteException;
import org.nakedobjects.nof.reflect.remote.data.ClientActionResultData;
import org.nakedobjects.nof.reflect.remote.data.CollectionData;
import org.nakedobjects.nof.reflect.remote.data.CriteriaData;
import org.nakedobjects.nof.reflect.remote.data.Data;
import org.nakedobjects.nof.reflect.remote.data.IdentityData;
import org.nakedobjects.nof.reflect.remote.data.KnownObjects;
import org.nakedobjects.nof.reflect.remote.data.NullData;
import org.nakedobjects.nof.reflect.remote.data.ObjectData;
import org.nakedobjects.nof.reflect.remote.data.ObjectEncoder;
import org.nakedobjects.nof.reflect.remote.data.ReferenceData;
import org.nakedobjects.nof.reflect.remote.data.ServerActionResultData;
import org.nakedobjects.nof.reflect.remote.data.ValueData;
import org.nakedobjects.nos.remote.command.DataFactory;
public class Marshaller implements ObjectEncoder {
private final BasicObjectSerializer encoder = new BasicObjectSerializer();
private final BasicObjectDeserializer decoder = new BasicObjectDeserializer();
private final DataStructure dataStructure = new DataStructure();
private final Map criteriaStragies = new HashMap();
private DataFactory factory;
private int actionGraphDepth = 0;
private int persistentGraphDepth = 100;
private int updateGraphDepth = 1;
{
encoder.setDataStructure(dataStructure);
decoder.setDataStructure(dataStructure);
addCriteriaStrategy(new AllInstancesEncoder());
addCriteriaStrategy(new FindByTitleEncoder());
addCriteriaStrategy(new PatternCriteriaEncoder());
addCriteriaStrategy(new PerspectiveCriteriaEncoder());
}
public void addCriteriaStrategy(final CriteriaEncoding encoder) {
criteriaStragies.put(encoder.getCriteriaClass(), encoder);
}
public ReferenceData createActionTarget(NakedObject target, KnownObjects knownObjects) {
return encoder.serializeObject(factory, target, actionGraphDepth, knownObjects);
}
public ClientActionResultData createClientActionResult(
final ReferenceData[] madePersistent,
final Version[] changedVersion,
ObjectData[] updates) {
return factory.createClientActionResultData(madePersistent, changedVersion, updates);
}
public final ObjectData createCompletePersistentGraph(NakedObject object) {
return (ObjectData) encoder.serializeObject(factory, object, persistentGraphDepth, new KnownObjects());
}
public CriteriaData createCriteriaData(InstancesCriteria criteria) {
CriteriaEncoding strategy = findCriteriaEncoder(criteria.getClass());
return strategy.createData(criteria, this);
}
public Data createForResolveField(NakedObject object, String fieldName) {
Oid oid = object.getOid();
NakedObjectSpecification specification = object.getSpecification();
String type = specification.getFullName();
ResolveState resolveState = object.getResolveState();
Data[] fieldContent;
NakedObjectField[] fields = getFieldOrder(specification);
fieldContent = new Data[fields.length];
NakedObjectsContext.getObjectLoader().start(object, object.getResolveState().serializeFrom());
KnownObjects knownObjects = new KnownObjects();
for (int i = 0; i < fields.length; i++) {
if (fields[i].getId().equals(fieldName)) {
Naked field = fields[i].get(object);
if (field == null) {
fieldContent[i] = factory.createNullData(fields[i].getSpecification().getFullName());
} else if (fields[i].isValue()) {
fieldContent[i] = encoder.serializeValue(factory, field);
} else if (fields[i].isCollection()) {
fieldContent[i] = encoder.serializeCollection(factory, (NakedCollection) field, persistentGraphDepth,
knownObjects);
} else {
NakedObjectsContext.getObjectPersistor().resolveImmediately((NakedObject) field);
fieldContent[i] = encoder.serializeObject(factory, (NakedObject) field, persistentGraphDepth, knownObjects);
}
break;
}
}
NakedObjectsContext.getObjectLoader().end(object);
// TODO remove the fudge - needed as collections are part of parents, hence parent object gets set as
// resolving (is not a ghost) yet it has no version number
// return createObjectData(oid, type, fieldContent, resolveState.isResolved(),
// !resolveState.isGhost(), object.getVersion());
ObjectData data = factory.createObjectData(type, oid, resolveState.isResolved(), object.getVersion());
data.setFieldContent(fieldContent);
return data;
// return createObjectData(oid, type, fieldContent, resolveState.isResolved(), object.getVersion());
}
public ObjectData createForUpdate(NakedObject object) {
ResolveState resolveState = object.getResolveState();
if (resolveState.isSerializing() || resolveState.isGhost()) {
throw new NakedObjectsRemoteException("Illegal resolve state: " + object);
}
return (ObjectData) encoder.serializeObject(factory, object, updateGraphDepth, new KnownObjects());
}
public ObjectData createGraphForChangedObject(NakedObject object, KnownObjects knownObjects) {
return (ObjectData) encoder.serializeObject(factory, object, 1, knownObjects);
}
/**
* Creates a ReferenceData that contains the type, version and OID for the specified object. This can only
* be used for persistent objects.
*/
public final IdentityData createIdentityData(NakedObject object) {
Assert.assertNotNull("OID needed for reference", object, object.getOid());
return factory.createIdentityData(object.getSpecification().getFullName(), object.getOid(), object.getVersion());
}
private Data createMadePersistentCollection(final CollectionData collectionData, final NakedCollection collection) {
ReferenceData[] elementData = collectionData.getElements();
Enumeration elements = collection.elements();
for (int i = 0; i < elementData.length; i++) {
NakedObject element = (NakedObject) elements.nextElement();
Oid oid = element.getOid();
Assert.assertNotNull(oid);
elementData[i] = createMadePersistentGraph((ObjectData) elementData[i], element);
}
return collectionData;
}
public ObjectData createMadePersistentGraph(final ObjectData data, final NakedObject object) {
Oid objectsOid = object.getOid();
Assert.assertNotNull(objectsOid);
if (objectsOid.hasPrevious()) {
Version version = object.getVersion();
String type = data.getType();
ObjectData persistedData = factory.createObjectData(type, objectsOid, true, version);
Data[] allContents = data.getFieldContent();
if (allContents != null) {
int contentLength = allContents.length;
Data persistentContents[] = new Data[contentLength];
NakedObjectField[] fields = getFieldOrder(object.getSpecification());
for (int i = 0; i < contentLength; i++) {
Data fieldData = allContents[i];
if (fieldData instanceof NullData) {
persistentContents[i] = null;
} else if (fields[i].isObject()) {
if (fieldData instanceof ObjectData) {
NakedObject fieldReference = (NakedObject) fields[i].get(object);
persistentContents[i] = createMadePersistentGraph((ObjectData) fieldData, fieldReference);
} else {
persistentContents[i] = null;
}
} else if (fields[i].isCollection()) {
NakedCollection fieldReference = (NakedCollection) fields[i].get(object);
persistentContents[i] = createMadePersistentCollection((CollectionData) fieldData, fieldReference);
}
}
persistedData.setFieldContent(persistentContents);
}
return persistedData;
} else {
return null;
}
}
public ObjectData createMakePersistentGraph(NakedObject object, KnownObjects knownObjects) {
Assert.assertTrue("transient", object.getResolveState().isTransient());
return (ObjectData) encoder.serializeObject(factory, object, 1, knownObjects);
}
private final Data createParameter(String type, Naked object, KnownObjects knownObjects) {
if (object == null) {
return factory.createNullData(type);
}
if (object.getSpecification().getType() == NakedObjectSpecification.OBJECT) {
NakedObject nakedObject = (NakedObject) object;
return encoder.serializeObject(factory, nakedObject, 0, knownObjects);
} else if (object.getSpecification().getType() == NakedObjectSpecification.VALUE) {
return encoder.serializeValue(factory, object);
} else {
throw new UnknownTypeException(object.getSpecification());
}
}
public final Data[] createParameters(NakedObjectSpecification[] parameterTypes, Naked[] parameters, KnownObjects knownObjects) {
Data parameterData[] = new Data[parameters.length];
for (int i = 0; i < parameters.length; i++) {
Naked parameter = parameters[i];
String type = parameterTypes[i].getFullName();
parameterData[i] = createParameter(type, parameter, knownObjects);
}
return parameterData;
}
public ServerActionResultData createServerActionResult(
Naked result,
ObjectData[] updates,
ReferenceData[] disposed,
ObjectData persistedTarget,
ObjectData[] persistedParameters,
String[] messages, String[] warnings) {
Data result1;
if (result == null) {
result1 = factory.createNullData("");
} else if (result instanceof NakedCollection) {
result1 = encoder.serializeCollection(factory, (NakedCollection) result, persistentGraphDepth, new KnownObjects());
} else if (result instanceof NakedObject) {
result1 = createCompletePersistentGraph((NakedObject) result);
} else {
throw new UnknownTypeException(result);
}
return factory.createServerActionResultData(result1, updates, disposed, persistedTarget, persistedParameters, messages, warnings);
}
public ValueData createValue(NakedValue value) {
return encoder.serializeValue(factory, value);
}
public ObjectData createObject(final NakedObject object) {
return (ObjectData) encoder.serializeObject(factory, object, 0, new KnownObjects());
}
public NakedObjectField[] getFieldOrder(NakedObjectSpecification specification) {
return dataStructure.getFields(specification);
}
public void madePersistent(NakedObject target, ObjectData persistedTarget) {
decoder.madePersistent(target, persistedTarget);
}
public Naked restore(Data data) {
return decoder.restore(data);
}
public Naked restore(Data data, KnownObjects knownObjects) {
return decoder.restore(data, knownObjects);
}
public InstancesCriteria restoreCriteria(CriteriaData criteriaData) {
Class criteriaClass = criteriaData.getCriteriaClass();
CriteriaEncoding strategy = findCriteriaEncoder(criteriaClass);
return strategy.restore(criteriaData, this);
}
private CriteriaEncoding findCriteriaEncoder(Class criteriaClass) {
CriteriaEncoding strategy = (CriteriaEncoding) criteriaStragies.get(criteriaClass);
if (strategy == null) {
throw new NakedObjectsRemoteException("No encoding strategy for " + criteriaClass.getName());
}
return strategy;
}
/**
* .NET property
*
* @property
* @see #setActionGraphDepth(int)
*/
public void set_ActionGraphDepth(final int actionGraphDepth) {
setActionGraphDepth(actionGraphDepth);
}
/**
* .NET property
*
* @property
* @see #setPersistentGraphDepth(int)
*/
public void set_PersistentGraphDepth(final int persistentGraphDepth) {
setPersistentGraphDepth(persistentGraphDepth);
}
/**
* .NET property
*
* @property
* @see #setUpdateGraphDepth(int)
*/
public void set_UpdateGraphDepth(final int updateGraphDepth) {
setUpdateGraphDepth(updateGraphDepth);
}
/**
* Specifies the maximum depth to recurse when creating data graphs for the method
* createDataForActionTarget. Defaults to 100.
*/
public void setActionGraphDepth(final int actionGraphDepth) {
this.actionGraphDepth = actionGraphDepth;
}
/**
* .NET property
*
* @property
*/
public void set_DataFactory(final DataFactory factory) {
setDataFactory(factory);
}
public void setDataFactory(final DataFactory factory) {
this.factory = factory;
}
/**
* Specifies the maximum depth to recurse when creating data graphs of persistent objects. Defaults to
* 100.
*/
public void setPersistentGraphDepth(final int persistentGraphDepth) {
this.persistentGraphDepth = persistentGraphDepth;
}
/**
* Specifies the maximum depth to recurse when creating data graphs for updates. Defaults to 1.
*/
public void setUpdateGraphDepth(final int updateGraphDepth) {
this.updateGraphDepth = updateGraphDepth;
}
}
// Copyright (c) Naked Objects Group Ltd.
© 2015 - 2025 Weber Informatics LLC | Privacy Policy