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

org.nakedobjects.plugins.remoting.shared.ObjectEncoderImpl Maven / Gradle / Ivy

package org.nakedobjects.plugins.remoting.shared;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.nakedobjects.metamodel.adapter.NakedObject;
import org.nakedobjects.metamodel.adapter.ResolveState;
import org.nakedobjects.metamodel.adapter.oid.Oid;
import org.nakedobjects.metamodel.adapter.version.Version;
import org.nakedobjects.metamodel.commons.ensure.Assert;
import org.nakedobjects.metamodel.commons.exceptions.UnknownTypeException;
import org.nakedobjects.metamodel.criteria.InstancesCriteria;
import org.nakedobjects.metamodel.facets.collections.modify.CollectionFacet;
import org.nakedobjects.metamodel.spec.NakedObjectSpecification;
import org.nakedobjects.metamodel.spec.feature.NakedObjectAssociation;
import org.nakedobjects.metamodel.util.CollectionFacetUtils;
import org.nakedobjects.plugins.remoting.shared.data.ClientActionResultData;
import org.nakedobjects.plugins.remoting.shared.data.CollectionData;
import org.nakedobjects.plugins.remoting.shared.data.CriteriaData;
import org.nakedobjects.plugins.remoting.shared.data.Data;
import org.nakedobjects.plugins.remoting.shared.data.DataFactory;
import org.nakedobjects.plugins.remoting.shared.data.EncodeableObjectData;
import org.nakedobjects.plugins.remoting.shared.data.IdentityData;
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.PersistorUtil;

public class ObjectEncoderImpl implements ObjectEncoder {
    private final ObjectEncoderSerializer encoder = new ObjectEncoderSerializer();
    private final ObjectEncoderDeserializer decoder = new ObjectEncoderDeserializer();
    private final ObjectEncoderDataStructure dataStructure = new ObjectEncoderDataStructure();
    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 CriteriaEncoderAllInstances());
        addCriteriaStrategy(new CriteriaEncoderFindByTitle());
        addCriteriaStrategy(new CriteriaEncoderPattern());
    }

    public void addCriteriaStrategy(final CriteriaEncoder encoder) {
        criteriaStragies.put(encoder.getCriteriaClass(), encoder);
    }

    public ReferenceData createActionTarget(final NakedObject target, final KnownObjects knownObjects) {
        return encoder.serializeObject(factory, target, actionGraphDepth, knownObjects);
    }

    public ClientActionResultData createClientActionResult(
            final ReferenceData[] madePersistent,
            final Version[] changedVersion,
            final ObjectData[] updates) {
        return factory.createClientActionResultData(madePersistent, changedVersion, updates);
    }

    public final ObjectData createCompletePersistentGraph(final NakedObject object) {
        return (ObjectData) encoder.serializeObject(factory, object, persistentGraphDepth, new KnownObjects());
    }

    public CriteriaData createCriteriaData(final InstancesCriteria criteria) {
        final CriteriaEncoder strategy = findCriteriaEncoder(criteria.getClass());
        return strategy.createData(criteria, this);
    }

    public Data createForResolveField(final NakedObject adapter, final String fieldName) {
        final Oid oid = adapter.getOid();
        final NakedObjectSpecification specification = adapter.getSpecification();
        final String type = specification.getFullName();
        final ResolveState resolveState = adapter.getResolveState();

        Data[] fieldContent;
        final NakedObjectAssociation[] fields = getFieldOrder(specification);
        fieldContent = new Data[fields.length];

        PersistorUtil.start(adapter, adapter.getResolveState().serializeFrom());
        final KnownObjects knownObjects = new KnownObjects();
        for (int i = 0; i < fields.length; i++) {
            if (fields[i].getId().equals(fieldName)) {
                final NakedObject field = fields[i].get(adapter);
                if (field == null) {
                    fieldContent[i] = factory.createNullData(fields[i].getSpecification().getFullName());
                } else if (fields[i].getSpecification().isEncodeable()) {
                    fieldContent[i] = encoder.serializeEncodeable(factory, field);
                } else if (fields[i].isOneToManyAssociation()) {
                    fieldContent[i] = encoder.serializeCollection(factory, field, persistentGraphDepth, knownObjects);
                } else {
                    NakedObjectsContext.getPersistenceSession().resolveImmediately(field);
                    fieldContent[i] = encoder.serializeObject(factory, field, persistentGraphDepth, knownObjects);
                }
                break;
            }
        }
        PersistorUtil.end(adapter);

        // 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());
        final ObjectData data = factory.createObjectData(type, oid, resolveState.isResolved(), adapter.getVersion());
        data.setFieldContent(fieldContent);
        return data;
        // return createObjectData(oid, type, fieldContent, resolveState.isResolved(), object.getVersion());
    }

    public ObjectData createForUpdate(final NakedObject object) {
        final 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(final NakedObject object, final 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(final 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 NakedObject collection) {
        final ReferenceData[] elementData = collectionData.getElements();
        final CollectionFacet facet = CollectionFacetUtils.getCollectionFacetFromSpec(collection);
        final Iterator elements = facet.iterator(collection);
        for (int i = 0; i < elementData.length; i++) {
            final NakedObject element = (NakedObject) elements.next();
            final 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) {
        final Oid objectsOid = object.getOid();
        Assert.assertNotNull(objectsOid);
        if (objectsOid.hasPrevious()) {
            final Version version = object.getVersion();
            final String type = data.getType();
            final ObjectData persistedData = factory.createObjectData(type, objectsOid, true, version);

            final Data[] allContents = data.getFieldContent();
            if (allContents != null) {
                final int contentLength = allContents.length;
                final Data persistentContents[] = new Data[contentLength];
                final NakedObjectAssociation[] fields = getFieldOrder(object.getSpecification());
                for (int i = 0; i < contentLength; i++) {
                    final Data fieldData = allContents[i];
                    if (fieldData instanceof NullData) {
                        persistentContents[i] = null;
                    } else if (fields[i].isOneToOneAssociation()) {
                        if (fieldData instanceof ObjectData) {
                            final NakedObject fieldReference = fields[i].get(object);
                            persistentContents[i] = createMadePersistentGraph((ObjectData) fieldData, fieldReference);
                        } else {
                            persistentContents[i] = null;
                        }
                    } else if (fields[i].isOneToManyAssociation()) {
                        final NakedObject fieldReference = fields[i].get(object);
                        persistentContents[i] = createMadePersistentCollection((CollectionData) fieldData, fieldReference);
                    }
                }
                persistedData.setFieldContent(persistentContents);
            }

            return persistedData;
        } else {
            return null;
        }
    }

    public ObjectData createMakePersistentGraph(final NakedObject adapter, final KnownObjects knownObjects) {
        Assert.assertTrue("transient", adapter.isTransient());
        return (ObjectData) encoder.serializeObject(factory, adapter, 1, knownObjects);
    }

    private final Data createParameter(final String type, final NakedObject object, final KnownObjects knownObjects) {
        if (object == null) {
            return factory.createNullData(type);
        }

        if (object.getSpecification().isObject()) {
            if (object.getSpecification().isEncodeable()) {
                return encoder.serializeEncodeable(factory, object);
            } else {
                final NakedObject nakedObject = object;
                return encoder.serializeObject(factory, nakedObject, 0, knownObjects);
            }
        } else {
            throw new UnknownTypeException(object.getSpecification());
        }
    }

    public final Data[] createParameters(
            final NakedObjectSpecification[] parameterTypes,
            final NakedObject[] parameters,
            final KnownObjects knownObjects) {
        final Data parameterData[] = new Data[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            final NakedObject parameter = parameters[i];
            final String type = parameterTypes[i].getFullName();
            parameterData[i] = createParameter(type, parameter, knownObjects);
        }
        return parameterData;
    }

    public ServerActionResultData createServerActionResult(
            final NakedObject result,
            final ObjectData[] updates,
            final ReferenceData[] disposed,
            final ObjectData persistedTarget,
            final ObjectData[] persistedParameters,
            final String[] messages,
            final String[] warnings) {
        Data result1;
        if (result == null) {
            result1 = factory.createNullData("");
        } else if (result.getSpecification().isCollection()) {
            result1 = encoder.serializeCollection(factory, result, persistentGraphDepth, new KnownObjects());
        } else if (result.getSpecification().isObject()) {
            result1 = createCompletePersistentGraph(result);
        } else {
            throw new UnknownTypeException(result);
        }

        return factory.createServerActionResultData(result1, updates, disposed, persistedTarget, persistedParameters, messages,
                warnings);
    }

    public EncodeableObjectData createValue(final NakedObject value) {
        return encoder.serializeEncodeable(factory, value);
    }

    public ObjectData createObject(final NakedObject object) {
        return (ObjectData) encoder.serializeObject(factory, object, 0, new KnownObjects());
    }

    public NakedObjectAssociation[] getFieldOrder(final NakedObjectSpecification specification) {
        return dataStructure.getFields(specification);
    }

    public void madePersistent(final NakedObject target, final ObjectData persistedTarget) {
        decoder.madePersistent(target, persistedTarget);
    }

    public NakedObject restore(final Data data) {
        return decoder.restore(data);
    }

    public NakedObject restore(final Data data, final KnownObjects knownObjects) {
        return decoder.restore(data, knownObjects);
    }

    public InstancesCriteria restoreCriteria(final CriteriaData criteriaData) {
        final Class criteriaClass = criteriaData.getCriteriaClass();
        final CriteriaEncoder strategy = findCriteriaEncoder(criteriaClass);
        return strategy.restore(criteriaData, this);
    }

    private CriteriaEncoder findCriteriaEncoder(final Class criteriaClass) {
        final CriteriaEncoder strategy = (CriteriaEncoder) 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