
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