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

org.nakedobjects.nos.remote.command.marshal.Marshaller Maven / Gradle / Ivy

There is a newer version: 3.0.3
Show newest version
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