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

org.nakedobjects.plugins.remoting.client.persistence.PersistenceSessionProxy Maven / Gradle / Ivy

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

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Vector;

import org.apache.log4j.Logger;
import org.nakedobjects.metamodel.adapter.NakedObject;
import org.nakedobjects.metamodel.adapter.ResolveState;
import org.nakedobjects.metamodel.adapter.oid.Oid;
import org.nakedobjects.metamodel.authentication.AuthenticationSession;
import org.nakedobjects.metamodel.commons.component.ApplicationScopedComponent;
import org.nakedobjects.metamodel.commons.component.SessionScopedComponent;
import org.nakedobjects.metamodel.commons.debug.DebugString;
import org.nakedobjects.metamodel.criteria.InstancesCriteria;
import org.nakedobjects.metamodel.facets.collections.modify.CollectionFacet;
import org.nakedobjects.metamodel.services.ServicesInjector;
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.ObjectEncoder;
import org.nakedobjects.plugins.remoting.shared.ServerFacade;
import org.nakedobjects.plugins.remoting.shared.data.CriteriaData;
import org.nakedobjects.plugins.remoting.shared.data.Data;
import org.nakedobjects.plugins.remoting.shared.data.IdentityData;
import org.nakedobjects.plugins.remoting.shared.data.ObjectData;
import org.nakedobjects.runtime.context.NakedObjectsContext;
import org.nakedobjects.runtime.persistence.PersistenceSession;
import org.nakedobjects.runtime.persistence.PersistenceSessionAbstract;
import org.nakedobjects.runtime.persistence.PersistenceSessionFactory;
import org.nakedobjects.runtime.persistence.adapterfactory.AdapterFactory;
import org.nakedobjects.runtime.persistence.adaptermanager.AdapterManagerExtended;
import org.nakedobjects.runtime.persistence.objectfactory.ObjectFactory;
import org.nakedobjects.runtime.persistence.oidgenerator.OidGenerator;
import org.nakedobjects.runtime.transaction.updatenotifier.UpdateNotifier;


public class PersistenceSessionProxy extends PersistenceSessionAbstract {

    final static Logger LOG = Logger.getLogger(PersistenceSessionProxy.class);

    private ServerFacade connection;
    private ObjectEncoder encoder;

    private final Hashtable cache = new Hashtable();
    private HashMap services = new HashMap();


    //////////////////////////////////////////////////////////////////
    // Constructor
    //////////////////////////////////////////////////////////////////

    public PersistenceSessionProxy(
            final PersistenceSessionFactory persistenceSessionFactory,
            final AdapterFactory adapterFactory, 
            final ObjectFactory objectFactory, 
            final ServicesInjector containerInjector, 
            final OidGenerator oidGenerator, 
            final AdapterManagerExtended identityMap, 
            final ServerFacade distribution, 
            final ObjectEncoder encoder) {
        super(persistenceSessionFactory, adapterFactory, objectFactory, containerInjector, oidGenerator, identityMap);
        setConnection(distribution);
        setEncoder(encoder);
    }


    //////////////////////////////////////////////////////////////////
    // init, shutdown, reset, isInitialized
    //////////////////////////////////////////////////////////////////

    /**
     * TODO: mismatch between {@link SessionScopedComponent} (open) and
     * {@link ApplicationScopedComponent} (init).
     */
    @Override
    public void doOpen() {
        connection.init();
    }

    /**
     * TODO: mismatch between {@link SessionScopedComponent} (open) and
     * {@link ApplicationScopedComponent} (init).
     */
    public void doClose() {
        connection.shutdown();
    }


    /**
     * No need to install fixtures, rely on server-side to do the right thing. 
     */
    public boolean isFixturesInstalled() {
        return true;
    }


    //////////////////////////////////////////////////////////////////
    // objectChanged
    //////////////////////////////////////////////////////////////////

    public void objectChanged(final NakedObject adapter) {
        if (adapter.isTransient()) {
            getUpdateNotifier().addChangedObject(adapter);
        }

        if (adapter.getResolveState().respondToChangesInPersistentObjects()) {
            getClientSideTransactionManager().addObjectChanged(adapter);
        }
    }



    //////////////////////////////////////////////////////////////////
    // destroy
    //////////////////////////////////////////////////////////////////


    public synchronized void destroyObject(final NakedObject object) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("destroyObject " + object);
        }
        getClientSideTransactionManager().addDestroyObject(object);

        // TODO need to do garbage collection instead
        // NakedObjects.getObjectLoader().unloaded(object);
    }

    //////////////////////////////////////////////////////////////////
    // makePersistent
    //////////////////////////////////////////////////////////////////
    
    /**
     * REVIEW: we should perhaps have a little more symmetry here, and
     * have the {@link ServerFacade} callback to the {@link PersistenceSession}
     * (the PersistenceSessionPersist API) to handle remapping
     * of adapters.
     */
    public synchronized void makePersistent(final NakedObject object) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("makePersistent " + object);
        }
        getClientSideTransactionManager().addMakePersistent(object);

        // the two implementations vary here.
        // the object store does not make this call directly, it
        // instead delegates to the PersistAlgorithm that makes a
        // callback to the PersistenceSessionPersist API,
        // which in turn calls remaps the adapters.
        // 
        // the proxy persistor on the other hand does nothing here.
        // instead we remap the adapter in distribution code,
        // processing the handling of the returned results.
        //
        // (see REVIEW comment above)
        
        
        
    }



    //////////////////////////////////////////////////////////////////
    // getInstances, hasInstances
    //////////////////////////////////////////////////////////////////

    @Override
    protected NakedObject[] getInstances(final InstancesCriteria criteria) {
        final NakedObjectSpecification specification = criteria.getSpecification();
        LOG.debug("getInstances of " + specification + " with " + criteria);
        if (cache.containsKey(specification)) {
            final NakedObject collection = (NakedObject) cache.get(specification);
            if (collection.getSpecification().isCollection()) {
                final CollectionFacet facet = CollectionFacetUtils.getCollectionFacetFromSpec(collection);
                final Vector instances = new Vector();
                for (NakedObject instance : facet.iterable(collection)) {
                    if (criteria.matches(instance)) {
                        instances.addElement(instance);
                    }
                }
                return (NakedObject[]) instances.toArray(new NakedObject[instances.size()]);
            }
        }

        final CriteriaData criteriaData = encoder.createCriteriaData(criteria);
        final ObjectData[] instancesAsObjectData = connection.findInstances(getAuthenticationSession(), criteriaData);
        final NakedObject[] instances = new NakedObject[instancesAsObjectData.length];
        for (int i = 0; i < instancesAsObjectData.length; i++) {
            instances[i] = encoder.restore(instancesAsObjectData[i]);
        }
        clearAllDirty();
        return instances;
    }


    public boolean hasInstances(final NakedObjectSpecification specification) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("hasInstances of " + specification);
        }
        if (cache.containsKey(specification)) {
            final NakedObject collection = (NakedObject) cache.get(specification);
            final CollectionFacet facet = CollectionFacetUtils.getCollectionFacetFromSpec(collection);
            if (facet != null) {
                return facet.size(collection) > 0;
            }
        }

        return connection.hasInstances(getAuthenticationSession(), specification.getFullName());
    }


    //////////////////////////////////////////////////////////////////
    // loadObject, reload
    //////////////////////////////////////////////////////////////////

    public synchronized NakedObject loadObject(final Oid oid, final NakedObjectSpecification hint) {
        final NakedObject adapter = getAdapterManager().getAdapterFor(oid);
        if (adapter != null) {
            return adapter;
        }
        final ObjectData data = connection.getObject(null, oid, hint.getFullName());
        return encoder.restore(data);
    }

    public void reload(final NakedObject object) {
        IdentityData identityData = encoder.createIdentityData(object);
        final ObjectData update = connection.resolveImmediately(getAuthenticationSession(), identityData);
        encoder.restore(update);
    }

    
    //////////////////////////////////////////////////////////////////
    // resolveImmediately, resolveField
    //////////////////////////////////////////////////////////////////

    public synchronized void resolveImmediately(final NakedObject object) {
        final ResolveState resolveState = object.getResolveState();
        if (resolveState.canChangeTo(ResolveState.RESOLVING)) {
            final Oid oid = object.getOid();
            if (LOG.isDebugEnabled()) {
                LOG.debug("resolve object (remotely from server)" + oid);
            }
            final ObjectData data = connection.resolveImmediately(getAuthenticationSession(), encoder
                    .createIdentityData(object));
            encoder.restore(data);
        }
    }

    public void resolveField(final NakedObject objectAdapter, final NakedObjectAssociation field) {
        if (field.getSpecification().isMutableAggregated()) {
            return;
        }
        final NakedObject referenceAdapter = field.get(objectAdapter);
        if (referenceAdapter != null && referenceAdapter.getResolveState().isResolved()) {
            return;
        }
        if (referenceAdapter == null || !referenceAdapter.isPersistent()) {
            return;
        }

        LOG.info("resolve-eagerly on server " + objectAdapter + "/" + field.getId());
        final Data data = connection.resolveField(getAuthenticationSession(), encoder.createIdentityData(objectAdapter), field
                .getId());
        encoder.restore(data);
    }


    //////////////////////////////////////////////////////////////////
    // Services
    //////////////////////////////////////////////////////////////////

    @Override
    public Oid getOidForService(final String name) {
        Oid oid = services.get(name);
        if (oid == null) {
            final IdentityData data = connection.oidForService(getAuthenticationSession(), name);
            oid = data.getOid();
            registerService(name, oid);
        }
        return oid;
    }

    @Override
    public void registerService(final String name, final Oid oid) {
        services.put(name, oid);
    }


    //////////////////////////////////////////////////////////////////
    // Debugging
    //////////////////////////////////////////////////////////////////

    @Override
    public void debugData(final DebugString debug) {
        super.debugData(debug);
        debug.appendln("Connection", connection);
    }

    public String debugTitle() {
        return "Proxy Object Manager";
    }



    //////////////////////////////////////////////////////////////////
    // Dependencies (injected)
    //////////////////////////////////////////////////////////////////

    public void setCacheInstances(final String[] names) {
        for (int i = 0; i < names.length; i++) {
            final NakedObjectSpecification spec = NakedObjectsContext.getSpecificationLoader().loadSpecification(names[i]);
            cache.put(spec, Boolean.TRUE);
        }
    }


    public void setConnection(final ServerFacade connection) {
        this.connection = connection;
    }

    public void setEncoder(final ObjectEncoder factory) {
        this.encoder = factory;
    }

    
    /**
     * Downcasts.
     */
    private ClientSideTransactionManager getClientSideTransactionManager() {
        return (ClientSideTransactionManager) getTransactionManager();
    }



    //////////////////////////////////////////////////////////////////
    // Dependencies (from context)
    //////////////////////////////////////////////////////////////////
    
    private AuthenticationSession getAuthenticationSession() {
        return NakedObjectsContext.getAuthenticationSession();
    }

    private UpdateNotifier getUpdateNotifier() {
        return NakedObjectsContext.getUpdateNotifier();
    }



}
// Copyright (c) Naked Objects Group Ltd.




© 2015 - 2025 Weber Informatics LLC | Privacy Policy