You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2012/12/06 11:10:35 UTC

[35/51] [partial] ISIS-188: moving modules into core

http://git-wip-us.apache.org/repos/asf/isis/blob/dbb64345/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/PersistenceSessionFactoryDelegate.java
----------------------------------------------------------------------
diff --git a/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/PersistenceSessionFactoryDelegate.java b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/PersistenceSessionFactoryDelegate.java
new file mode 100644
index 0000000..9c0648f
--- /dev/null
+++ b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/PersistenceSessionFactoryDelegate.java
@@ -0,0 +1,76 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.runtimes.dflt.runtime.persistence;
+
+import org.apache.isis.applib.DomainObjectContainer;
+import org.apache.isis.core.commons.config.IsisConfiguration;
+import org.apache.isis.core.commons.config.IsisConfigurationBuilderAware;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapterFactory;
+import org.apache.isis.core.metamodel.facetapi.ClassSubstitutorFactory;
+import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
+import org.apache.isis.core.metamodel.runtimecontext.RuntimeContext;
+import org.apache.isis.core.metamodel.services.ServicesInjectorSpi;
+import org.apache.isis.runtimes.dflt.runtime.persistence.adaptermanager.PojoRecreator;
+import org.apache.isis.runtimes.dflt.runtime.system.persistence.IdentifierGenerator;
+import org.apache.isis.runtimes.dflt.runtime.system.persistence.ObjectFactory;
+import org.apache.isis.runtimes.dflt.runtime.system.persistence.PersistenceSession;
+import org.apache.isis.runtimes.dflt.runtime.system.persistence.PersistenceSessionFactory;
+
+/**
+ * Creates a {@link PersistenceSession} on behalf of a
+ * {@link PersistenceSessionFactory}.
+ */
+public interface PersistenceSessionFactoryDelegate extends IsisConfigurationBuilderAware, ClassSubstitutorFactory, MetaModelRefiner {
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // singleton threadsafe components created during init
+    ///////////////////////////////////////////////////////////////////////////
+    
+    PojoRecreator createPojoRecreator(IsisConfiguration configuration);
+
+    ObjectAdapterFactory createAdapterFactory(IsisConfiguration configuration);
+
+    ObjectFactory createObjectFactory(IsisConfiguration configuration);
+
+    IdentifierGenerator createIdentifierGenerator(IsisConfiguration configuration);
+
+    ServicesInjectorSpi createServicesInjector(IsisConfiguration configuration);
+
+    DomainObjectContainer createContainer(IsisConfiguration configuration);
+
+    RuntimeContext createRuntimeContext(IsisConfiguration configuration);
+
+    
+    ///////////////////////////////////////////////////////////////////////////
+    // created for each session
+    ///////////////////////////////////////////////////////////////////////////
+
+    /**
+     * As per {@link PersistenceSessionFactory#createPersistenceSession()}, but
+     * passing a {@link PersistenceSessionFactory} to act as the
+     * {@link PersistenceSession}'s
+     * {@link PersistenceSession#getPersistenceSessionFactory() owning factory}.
+     */
+    PersistenceSession createPersistenceSession(PersistenceSessionFactory persistenceSessionFactory);
+
+    
+    
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/dbb64345/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/PersistenceSessionFactoryDelegating.java
----------------------------------------------------------------------
diff --git a/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/PersistenceSessionFactoryDelegating.java b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/PersistenceSessionFactoryDelegating.java
new file mode 100644
index 0000000..d476e2c
--- /dev/null
+++ b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/PersistenceSessionFactoryDelegating.java
@@ -0,0 +1,261 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.runtimes.dflt.runtime.persistence;
+
+import static org.apache.isis.core.commons.ensure.Ensure.ensureThatArg;
+import static org.apache.isis.core.commons.ensure.Ensure.ensureThatState;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.nullValue;
+
+import java.util.List;
+
+import org.apache.isis.applib.DomainObjectContainer;
+import org.apache.isis.applib.clock.Clock;
+import org.apache.isis.applib.fixtures.FixtureClock;
+import org.apache.isis.core.commons.config.IsisConfiguration;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapterFactory;
+import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
+import org.apache.isis.core.metamodel.runtimecontext.RuntimeContext;
+import org.apache.isis.core.metamodel.services.ServicesInjectorSpi;
+import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpi;
+import org.apache.isis.core.metamodel.specloader.classsubstitutor.ClassSubstitutor;
+import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidator;
+import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorComposite;
+import org.apache.isis.runtimes.dflt.runtime.persistence.adaptermanager.PojoRecreator;
+import org.apache.isis.runtimes.dflt.runtime.system.DeploymentType;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+import org.apache.isis.runtimes.dflt.runtime.system.persistence.IdentifierGenerator;
+import org.apache.isis.runtimes.dflt.runtime.system.persistence.ObjectFactory;
+import org.apache.isis.runtimes.dflt.runtime.system.persistence.PersistenceSession;
+import org.apache.isis.runtimes.dflt.runtime.system.persistence.PersistenceSessionFactory;
+
+/**
+ * Implementation that just delegates to a supplied
+ * {@link PersistenceSessionFactory}.
+ */
+public class PersistenceSessionFactoryDelegating implements PersistenceSessionFactory, FixturesInstalledFlag {
+
+    private final DeploymentType deploymentType;
+    private final IsisConfiguration configuration;
+    private final PersistenceSessionFactoryDelegate persistenceSessionFactoryDelegate;
+    
+    private List<Object> serviceList;
+
+    private Boolean fixturesInstalled;
+    
+    private PojoRecreator pojoRecreator;
+    private ObjectAdapterFactory adapterFactory;
+    private ObjectFactory objectFactory;
+    private IdentifierGenerator identifierGenerator;
+    private ServicesInjectorSpi servicesInjector;
+    private DomainObjectContainer container;
+    private RuntimeContext runtimeContext;
+
+    public PersistenceSessionFactoryDelegating(final DeploymentType deploymentType, final IsisConfiguration isisConfiguration, final PersistenceSessionFactoryDelegate persistenceSessionFactoryDelegate) {
+        this.deploymentType = deploymentType;
+        this.configuration = isisConfiguration;
+        this.persistenceSessionFactoryDelegate = persistenceSessionFactoryDelegate;
+    }
+
+    @Override
+    public DeploymentType getDeploymentType() {
+        return deploymentType;
+    }
+
+    public PersistenceSessionFactoryDelegate getDelegate() {
+        return persistenceSessionFactoryDelegate;
+    }
+
+    @Override
+    public PersistenceSession createPersistenceSession() {
+        return persistenceSessionFactoryDelegate.createPersistenceSession(this);
+    }
+
+    @Override
+    public final void init() {
+
+        // check prereq dependencies injected
+        ensureThatState(serviceList, is(notNullValue()));
+
+        // a bit of a workaround, but required if anything in the metamodel (for
+        // example, a
+        // ValueSemanticsProvider for a date value type) needs to use the Clock
+        // singleton
+        // we do this after loading the services to allow a service to prime a
+        // different clock
+        // implementation (eg to use an NTP time service).
+        if (!deploymentType.isProduction() && !Clock.isInitialized()) {
+            FixtureClock.initialize();
+        }
+
+        pojoRecreator = persistenceSessionFactoryDelegate.createPojoRecreator(getConfiguration());
+        adapterFactory = persistenceSessionFactoryDelegate.createAdapterFactory(getConfiguration());
+        objectFactory = persistenceSessionFactoryDelegate.createObjectFactory(getConfiguration());
+        identifierGenerator = persistenceSessionFactoryDelegate.createIdentifierGenerator(getConfiguration());
+
+        ensureThatState(pojoRecreator, is(not(nullValue())));
+        ensureThatState(adapterFactory, is(not(nullValue())));
+        ensureThatState(objectFactory, is(not(nullValue())));
+        ensureThatState(identifierGenerator, is(not(nullValue())));
+
+        servicesInjector = persistenceSessionFactoryDelegate.createServicesInjector(getConfiguration());
+        container = persistenceSessionFactoryDelegate.createContainer(getConfiguration());
+
+        ensureThatState(servicesInjector, is(not(nullValue())));
+        ensureThatState(container, is(not(nullValue())));
+
+        runtimeContext = persistenceSessionFactoryDelegate.createRuntimeContext(getConfiguration());
+        ensureThatState(runtimeContext, is(not(nullValue())));
+
+        
+        // wire up components
+
+        getSpecificationLoader().injectInto(runtimeContext);
+        runtimeContext.injectInto(container);
+        runtimeContext.setContainer(container);
+        for (Object service : serviceList) {
+            runtimeContext.injectInto(service);
+        }
+
+        servicesInjector.setContainer(container);
+        servicesInjector.setServices(serviceList);
+        servicesInjector.init();
+    }
+
+
+    @Override
+    public final void shutdown() {
+        doShutdown();
+    }
+
+    /**
+     * Optional hook method for implementation-specific shutdown.
+     */
+    protected void doShutdown() {
+    }
+
+    
+    // //////////////////////////////////////////////////////
+    // Components (setup during init...)
+    // //////////////////////////////////////////////////////
+
+    public ObjectAdapterFactory getAdapterFactory() {
+        return adapterFactory;
+    }
+    
+    public IdentifierGenerator getIdentifierGenerator() {
+        return identifierGenerator;
+    }
+    
+    public ObjectFactory getObjectFactory() {
+        return objectFactory;
+    }
+    
+    public PojoRecreator getPojoRecreator() {
+        return pojoRecreator;
+    }
+
+    public RuntimeContext getRuntimeContext() {
+        return runtimeContext;
+    }
+    
+    public ServicesInjectorSpi getServicesInjector() {
+        return servicesInjector;
+    }
+    
+    public List<Object> getServiceList() {
+        return serviceList;
+    }
+
+    public DomainObjectContainer getContainer() {
+        return container;
+    }
+
+    // //////////////////////////////////////////////////////
+    // MetaModelAdjuster impl
+    // //////////////////////////////////////////////////////
+
+    @Override
+    public ClassSubstitutor createClassSubstitutor(final IsisConfiguration configuration) {
+        return persistenceSessionFactoryDelegate.createClassSubstitutor(configuration);
+    }
+
+    @Override
+    public void refineMetaModelValidator(MetaModelValidatorComposite metaModelValidator, IsisConfiguration configuration) {
+        persistenceSessionFactoryDelegate.refineMetaModelValidator(metaModelValidator, configuration);
+    }
+
+    @Override
+    public void refineProgrammingModel(ProgrammingModel baseProgrammingModel, IsisConfiguration configuration) {
+        persistenceSessionFactoryDelegate.refineProgrammingModel(baseProgrammingModel, configuration);
+    }
+
+
+    // //////////////////////////////////////////////////////
+    // FixturesInstalledFlag impl
+    // //////////////////////////////////////////////////////
+
+    @Override
+    public Boolean isFixturesInstalled() {
+        return fixturesInstalled;
+    }
+
+    @Override
+    public void setFixturesInstalled(final Boolean fixturesInstalled) {
+        this.fixturesInstalled = fixturesInstalled;
+    }
+
+    // //////////////////////////////////////////////////////
+    // Dependencies (injected from constructor)
+    // //////////////////////////////////////////////////////
+
+    public IsisConfiguration getConfiguration() {
+        return configuration;
+    }
+    
+    // //////////////////////////////////////////////////////
+    // Dependencies (injected via setters)
+    // //////////////////////////////////////////////////////
+
+    @Override
+    public List<Object> getServices() {
+        return serviceList;
+    }
+
+    @Override
+    public void setServices(final List<Object> serviceList) {
+        this.serviceList = serviceList;
+    }
+
+
+    // //////////////////////////////////////////////////////
+    // Dependencies (from context)
+    // //////////////////////////////////////////////////////
+
+    
+    protected SpecificationLoaderSpi getSpecificationLoader() {
+        return IsisContext.getSpecificationLoader();
+    }
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/dbb64345/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/PersistorUtil.java
----------------------------------------------------------------------
diff --git a/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/PersistorUtil.java b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/PersistorUtil.java
new file mode 100644
index 0000000..d8b6101
--- /dev/null
+++ b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/PersistorUtil.java
@@ -0,0 +1,75 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.runtimes.dflt.runtime.persistence;
+
+import org.apache.log4j.Logger;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.ResolveState;
+
+public class PersistorUtil {
+
+    private static final Logger LOG = Logger.getLogger(PersistorUtil.class);
+
+    private PersistorUtil() {
+    }
+
+    // //////////////////////////////////////////////////////////////////
+    // update resolve state
+    // //////////////////////////////////////////////////////////////////
+
+    public static void startResolvingOrUpdating(ObjectAdapter objectAdapter) {
+        if(objectAdapter.canTransitionToResolving()) {
+            startResolving(objectAdapter);
+        } else {
+            startUpdating(objectAdapter);
+        }
+    }
+
+    public static void startResolving(final ObjectAdapter adapter) {
+        changeTo(adapter, ResolveState.RESOLVING);
+    }
+
+    public static void startUpdating(final ObjectAdapter adapter) {
+        changeTo(adapter, ResolveState.UPDATING);
+    }
+
+    private static void changeTo(final ObjectAdapter adapter, final ResolveState state) {
+        changeTo("start ", adapter, state);
+    }
+
+    /**
+     * Marks the specified object as loaded: resolved, partly resolve or updated
+     * as specified by the second parameter. Attempting to specify any other
+     * state throws a run time exception.
+     */
+    public static void toEndState(final ObjectAdapter adapter) {
+        changeTo("end ", adapter, adapter.getResolveState().getEndState());
+    }
+
+    private static void changeTo(final String direction, final ObjectAdapter adapter, final ResolveState state) {
+        if (LOG.isTraceEnabled()) {
+            LOG.trace(direction + adapter + " as " + state.name());
+        }
+        adapter.changeState(state);
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/dbb64345/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/UnsupportedFindException.java
----------------------------------------------------------------------
diff --git a/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/UnsupportedFindException.java b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/UnsupportedFindException.java
new file mode 100644
index 0000000..968381f
--- /dev/null
+++ b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/UnsupportedFindException.java
@@ -0,0 +1,42 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.runtimes.dflt.runtime.persistence;
+
+import org.apache.isis.core.commons.exceptions.IsisException;
+
+public class UnsupportedFindException extends IsisException {
+    private static final long serialVersionUID = 1L;
+
+    public UnsupportedFindException() {
+        super();
+    }
+
+    public UnsupportedFindException(final String message) {
+        super(message);
+    }
+
+    public UnsupportedFindException(final Throwable cause) {
+        super(cause);
+    }
+
+    public UnsupportedFindException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/dbb64345/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adapter/PojoAdapter.java
----------------------------------------------------------------------
diff --git a/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adapter/PojoAdapter.java b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adapter/PojoAdapter.java
new file mode 100644
index 0000000..f1c7cdd
--- /dev/null
+++ b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adapter/PojoAdapter.java
@@ -0,0 +1,554 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.runtimes.dflt.runtime.persistence.adapter;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+
+import org.apache.isis.applib.profiles.Localization;
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.commons.ensure.Assert;
+import org.apache.isis.core.commons.ensure.Ensure;
+import org.apache.isis.core.commons.exceptions.IsisException;
+import org.apache.isis.core.commons.lang.ToString;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.ResolveState;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+import org.apache.isis.core.metamodel.adapter.oid.AggregatedOid;
+import org.apache.isis.core.metamodel.adapter.oid.Oid;
+import org.apache.isis.core.metamodel.adapter.oid.ParentedOid;
+import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
+import org.apache.isis.core.metamodel.adapter.version.Version;
+import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
+import org.apache.isis.core.metamodel.spec.ElementSpecificationProvider;
+import org.apache.isis.core.metamodel.spec.Instance;
+import org.apache.isis.core.metamodel.spec.InstanceAbstract;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.Specification;
+import org.apache.isis.core.metamodel.spec.SpecificationLoader;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+import org.apache.isis.runtimes.dflt.runtime.system.persistence.PersistenceSession;
+import org.apache.log4j.Logger;
+
+public class PojoAdapter extends InstanceAbstract implements ObjectAdapter {
+
+    private final static Logger LOG = Logger.getLogger(PojoAdapter.class);
+
+    private static final int INCOMPLETE_COLLECTION = -1;
+
+    private final SpecificationLoader specificationLoader;
+    private final AdapterManager objectAdapterLookup;
+    private final Localization localization;
+    
+    private Object pojo;
+    private Oid oid;
+    private ResolveState resolveState;
+
+    private String defaultTitle;
+
+    private ElementSpecificationProvider elementSpecificationProvider;
+
+    private AuthenticationSession authenticationSession;
+
+
+    // ///////////////////////////////////////////////////////////////////
+    // Constructor, finalizer
+    // ///////////////////////////////////////////////////////////////////
+
+    public PojoAdapter(final Object pojo, final Oid oid, SpecificationLoader specificationLoader, AdapterManager adapterManager, Localization localization, AuthenticationSession authenticationSession) {
+        this.specificationLoader = specificationLoader;
+        this.objectAdapterLookup = adapterManager;
+        this.localization = localization;
+        this.authenticationSession = authenticationSession;
+        
+        if (pojo instanceof ObjectAdapter) {
+            throw new IsisException("Adapter can't be used to adapt an adapter: " + pojo);
+        }
+        this.pojo = pojo;
+        this.oid = oid;
+        resolveState = ResolveState.NEW;
+    }
+
+    
+    // ///////////////////////////////////////////////////////////////////
+    // Specification
+    // ///////////////////////////////////////////////////////////////////
+
+    @Override
+    protected ObjectSpecification loadSpecification() {
+        final ObjectSpecification specification = specificationLoader.loadSpecification(getObject().getClass());
+        this.defaultTitle = "A" + (" " + specification.getSingularName()).toLowerCase();
+        return specification;
+    }
+
+    /**
+     * Downcasts {@link #getSpecification()}.
+     */
+    @Override
+    public ObjectSpecification getSpecification() {
+        return (ObjectSpecification) super.getSpecification();
+    }
+
+    // ///////////////////////////////////////////////////////////////////
+    // Object, replacePojo
+    // ///////////////////////////////////////////////////////////////////
+
+    @Override
+    public Object getObject() {
+        return pojo;
+    }
+
+    /**
+     * Sometimes it is necessary to manage the replacement of the underlying
+     * domain object (by another component such as an object store). This method
+     * allows the adapter to be kept while the domain object is replaced.
+     */
+    @Override
+    public void replacePojo(final Object pojo) {
+        this.pojo = pojo;
+    }
+
+
+    // ///////////////////////////////////////////////////////////////////
+    // ResolveState, changeState
+    // ///////////////////////////////////////////////////////////////////
+
+    @Override
+    public ResolveState getResolveState() {
+        return aggregateResolveState();
+    }
+
+
+    private ResolveState aggregateResolveState() {
+        return isAggregated() ? 
+                ((PojoAdapter)getAggregateRoot()).aggregateResolveState() : 
+                resolveState;
+    }
+
+
+
+    @Override
+    public void changeState(final ResolveState newState) {
+        if(isAggregated()) {
+            return; // no-op for aggregated objects.
+        }
+
+        final boolean validToChangeTo = resolveState.isValidToChangeTo(newState);
+        // don't call toString() since that could hit titleString() and we might
+        // be in the process of transitioning to ghost
+        Assert.assertTrue("oid= " + this.getOid() + "; can't change from " + resolveState.name() + " to " + newState.name(), validToChangeTo);
+
+        if (LOG.isTraceEnabled()) {
+            String oidString;
+            if (oid == null) {
+                oidString = "";
+            } else {
+                // don't call toString() in case in process of transitioning to
+                // ghost
+                oidString = "for " + this.getOid() + " ";
+            }
+            LOG.trace(oidString + "changing resolved state to " + newState.name());
+        }
+        resolveState = newState;
+    }
+
+    private boolean elementsLoaded() {
+        return isTransient() || this.isResolved();
+    }
+
+    // ///////////////////////////////////////////////////////////////////
+    // ResolveState
+    // ///////////////////////////////////////////////////////////////////
+
+    /**
+     * Just delegates to {@link #aggregateResolveState() resolve state}.
+     * 
+     * @see ResolveState#representsPersistent()
+     * @see #isTransient()
+     */
+    @Override
+    public boolean representsPersistent() {
+        return aggregateResolveState().representsPersistent();
+    }
+
+
+    /**
+     * Just delegates to {@link #aggregateResolveState() resolve state}.
+     * 
+     * @see ResolveState#isTransient()
+     * @see #representsPersistent()
+     */
+    @Override
+    public boolean isTransient() {
+        return aggregateResolveState().isTransient();
+    }
+
+    @Override
+    public boolean isNew() {
+        return aggregateResolveState().isNew();
+    }
+
+    @Override
+    public boolean isResolving() {
+        return aggregateResolveState().isResolving();
+    }
+
+    @Override
+    public boolean isResolved() {
+        return aggregateResolveState().isResolved();
+    }
+
+    @Override
+    public boolean isGhost() {
+        return aggregateResolveState().isGhost();
+    }
+
+    @Override
+    public boolean isUpdating() {
+        return aggregateResolveState().isUpdating();
+    }
+
+    @Override
+    public boolean isDestroyed() {
+        return aggregateResolveState().isDestroyed();
+    }
+
+
+    @Override
+    public boolean canTransitionToResolving() {
+        return aggregateResolveState().canTransitionToResolving();
+    }
+
+
+    @Override
+    public boolean isTitleAvailable() {
+        final ResolveState resolveState = aggregateResolveState();
+        return resolveState.isValue() || resolveState.isResolved();
+    }
+
+    /**
+     * If {@link #isGhost()}, then will become resolved.
+     */
+    @Override
+    public void markAsResolvedIfPossible() {
+        if (!canTransitionToResolving()) {
+            return;
+        } 
+        changeState(ResolveState.RESOLVING);
+        changeState(ResolveState.RESOLVED);
+    }
+
+
+    
+    // ///////////////////////////////////////////////////////////////////
+    // Oid
+    // ///////////////////////////////////////////////////////////////////
+
+    @Override
+    public Oid getOid() {
+        return oid;
+    }
+
+    @Override
+    public void replaceOid(Oid persistedOid) {
+        Ensure.ensureThatArg(oid, is(notNullValue())); // values have no oid, so cannot be replaced 
+        this.oid = persistedOid;
+    }
+
+    @Override
+    public boolean isParented() {
+        return oid instanceof ParentedOid;
+    }
+
+    @Override
+    public boolean isAggregated() {
+        return oid instanceof AggregatedOid;
+    }
+
+    @Override
+    public boolean isValue() {
+        // equivalently: aggregateResolveState().isValue();
+        return oid == null;
+    }
+
+    @Override
+    public ObjectAdapter getAggregateRoot() {
+        if(!isParented()) {
+            return this;
+        }
+        ParentedOid parentedOid = (ParentedOid) oid;
+        final Oid parentOid = parentedOid.getParentOid();
+        ObjectAdapter parentAdapter = objectAdapterLookup.getAdapterFor(parentOid);
+        if(parentAdapter == null) {
+            final Oid parentOidNowPersisted = getPersistenceSession().remappedFrom(parentOid);
+            parentAdapter = objectAdapterLookup.getAdapterFor(parentOidNowPersisted);
+        }
+        return parentAdapter;
+    }
+
+    
+
+    
+
+    // ///////////////////////////////////////////////////////////////////
+    // Version 
+    // (nb: delegates to parent if parented)
+    // ///////////////////////////////////////////////////////////////////
+
+    @Override
+    public Version getVersion() {
+        if(isParented()) {
+            return getAggregateRoot().getVersion();
+        } else {
+            return getOid().getVersion();
+        }
+    }
+
+
+    @Override
+    public void checkLock(final Version otherVersion) {
+        if(isParented()) {
+            getAggregateRoot().checkLock(otherVersion);
+            return;
+        }
+        final Version version = getOid().getVersion();
+        if (otherVersion != null && version != null && version.different(otherVersion)) {
+            LOG.info("concurrency conflict on " + this + " (" + otherVersion + ")");
+            throw new ConcurrencyException(getAuthenticationSession().getUserName(), getOid(), version, otherVersion);
+        }
+    }
+
+
+    @Override
+    public void setVersion(final Version version) {
+        if(isParented()) {
+            // ignored
+            return;
+        }
+        if (shouldSetVersion(version)) {
+            RootOid rootOid = (RootOid) getOid(); // since not parented
+            rootOid.setVersion(version);
+        }
+    }
+
+    private boolean shouldSetVersion(final Version otherVersion) {
+        final Version version = getOid().getVersion();
+        return version == null || otherVersion == null || otherVersion.different(version);
+    }
+
+    // ///////////////////////////////////////////////////////////////////
+    // Title, toString
+    // ///////////////////////////////////////////////////////////////////
+
+    /**
+     * Returns the title from the underlying business object.
+     * 
+     * <p>
+     * If the object has not yet been resolved the specification will be asked
+     * for a unresolved title, which could of been persisted by the persistence
+     * mechanism. If either of the above provides null as the title then this
+     * method will return a title relating to the name of the object type, e.g.
+     * "A Customer", "A Product".
+     */
+    @Override
+    public String titleString() {
+        if (getSpecification().isParentedOrFreeCollection()) {
+            final CollectionFacet facet = getSpecification().getFacet(CollectionFacet.class);
+            return collectionTitleString(facet);
+        } else {
+            return objectTitleString();
+        }
+    }
+
+    private String objectTitleString() {
+        if (isNew()) {
+            return "";
+        } 
+        if (getObject() instanceof String) {
+            return (String) getObject();
+        }
+        final ObjectSpecification specification = getSpecification();
+        String title = specification.getTitle(this, localization);
+        
+        // looking at the implementation of the preceding code, this can never happen;
+        // and removing it means we can get rid of the dependency on PersistenceSession.
+        
+//        if (title == null) {
+//            if (resolveState.isGhost()) {
+//                if (LOG.isInfoEnabled()) {
+//                    LOG.info("attempting to use unresolved object; resolving it immediately: oid=" + this.getOid());
+//                }
+//                getPersistenceSession().resolveImmediately(this);
+//            }
+//        }
+        
+        if (title == null) {
+            title = getDefaultTitle();
+        }
+        return title;
+    }
+
+    private String collectionTitleString(final CollectionFacet facet) {
+        final int size = elementsLoaded() ? facet.size(this) : INCOMPLETE_COLLECTION;
+        final ObjectSpecification elementSpecification = getElementSpecification();
+        if (elementSpecification == null || elementSpecification.getFullIdentifier().equals(Object.class.getName())) {
+            switch (size) {
+            case -1:
+                return "Objects";
+            case 0:
+                return "No objects";
+            case 1:
+                return "1 object";
+            default:
+                return size + " objects";
+            }
+        } else {
+            switch (size) {
+            case -1:
+                return elementSpecification.getPluralName();
+            case 0:
+                return "No " + elementSpecification.getPluralName();
+            case 1:
+                return "1 " + elementSpecification.getSingularName();
+            default:
+                return size + " " + elementSpecification.getPluralName();
+            }
+        }
+    }
+
+    @Override
+    public synchronized String toString() {
+        final ToString str = new ToString(this);
+        toString(str);
+
+        // don't do title of any entities. For persistence entities, might
+        // forces an unwanted resolve
+        // of the object. For transient objects, may not be fully initialized.
+
+        str.append("pojo-toString", pojo.toString());
+        str.appendAsHex("pojo-hash", pojo.hashCode());
+        return str.toString();
+    }
+
+    protected String getDefaultTitle() {
+        return defaultTitle;
+    }
+
+    protected void toString(final ToString str) {
+        str.append(aggregateResolveState().code());
+        final Oid oid = getOid();
+        if (oid != null) {
+            str.append(":");
+            str.append(oid.toString());
+        } else {
+            str.append(":-");
+        }
+        str.setAddComma();
+        if (getSpecificationNoLoad() == null) {
+            str.append("class", getObject().getClass().getName());
+        } else {
+            str.append("specification", getSpecification().getShortIdentifier());
+        }
+        if(getOid() != null) {
+            final Version version = getOid().getVersion();
+            str.append("version", version != null ? version.sequence() : null);
+        }
+    }
+
+    // ///////////////////////////////////////////////////////////////////
+    // IconName
+    // ///////////////////////////////////////////////////////////////////
+
+    /**
+     * Returns the name of the icon to use to represent this object.
+     */
+    @Override
+    public String getIconName() {
+        return getSpecification().getIconName(this);
+    }
+
+    // ///////////////////////////////////////////////////////////////////
+    // ElementType
+    // ///////////////////////////////////////////////////////////////////
+
+    @Override
+    public ObjectSpecification getElementSpecification() {
+        if (elementSpecificationProvider == null) {
+            return null;
+        }
+        return elementSpecificationProvider.getElementType();
+    }
+
+    @Override
+    public void setElementSpecificationProvider(final ElementSpecificationProvider elementSpecificationProvider) {
+        this.elementSpecificationProvider = elementSpecificationProvider;
+    }
+
+    // /////////////////////////////////////////////////////////////
+    // getInstance
+    // /////////////////////////////////////////////////////////////
+
+    /**
+     * Not supported by this implementation.
+     */
+    @Override
+    public Instance getInstance(final Specification specification) {
+        throw new UnsupportedOperationException();
+    }
+
+    // ///////////////////////////////////////////////////////////////////
+    // Fire Changes
+    // ///////////////////////////////////////////////////////////////////
+
+    /**
+     * Guaranteed to be called whenever this object is known to have changed
+     * (specifically, by the <tt>ObjectStorePersistor</tt>).
+     * 
+     * <p>
+     * This implementation does nothing, but subclasses (for example
+     * <tt>PojoAdapterX</tt>) might provide listeners.
+     */
+    @Override
+    public void fireChangedEvent() {
+    }
+
+
+    @Override
+    public boolean respondToChangesInPersistentObjects() {
+        return aggregateResolveState().respondToChangesInPersistentObjects();
+    }
+
+
+
+    
+    ////////////////////////////////////////////////////////////////////
+    // Dependencies (from context)
+    ////////////////////////////////////////////////////////////////////
+
+    protected PersistenceSession getPersistenceSession() {
+        return IsisContext.getPersistenceSession();
+    }
+
+    protected AuthenticationSession getAuthenticationSession() {
+        return authenticationSession;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/dbb64345/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adapter/PojoAdapterFactory.java
----------------------------------------------------------------------
diff --git a/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adapter/PojoAdapterFactory.java b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adapter/PojoAdapterFactory.java
new file mode 100644
index 0000000..fc5adbe
--- /dev/null
+++ b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adapter/PojoAdapterFactory.java
@@ -0,0 +1,50 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.runtimes.dflt.runtime.persistence.adapter;
+
+import org.apache.isis.applib.profiles.Localization;
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapterFactory;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+import org.apache.isis.core.metamodel.adapter.oid.Oid;
+import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpi;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+
+public class PojoAdapterFactory implements ObjectAdapterFactory {
+
+    @Override
+    public PojoAdapter createAdapter(final Object pojo, final Oid oid, AdapterManager adapterManager) {
+        return new PojoAdapter(pojo, oid, getSpecificationLoader(), adapterManager, getLocalization(), getAuthenticationSession());
+    }
+
+    
+    
+    protected AuthenticationSession getAuthenticationSession() {
+        return IsisContext.getAuthenticationSession();
+    }
+
+    protected SpecificationLoaderSpi getSpecificationLoader() {
+        return IsisContext.getSpecificationLoader();
+    }
+
+    protected Localization getLocalization() {
+        return IsisContext.getLocalization();
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/dbb64345/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adaptermanager/AdapterManagerDefault.java
----------------------------------------------------------------------
diff --git a/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adaptermanager/AdapterManagerDefault.java b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adaptermanager/AdapterManagerDefault.java
new file mode 100644
index 0000000..c8b50c3
--- /dev/null
+++ b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adaptermanager/AdapterManagerDefault.java
@@ -0,0 +1,808 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.runtimes.dflt.runtime.persistence.adaptermanager;
+
+import static org.apache.isis.core.commons.ensure.Ensure.ensureThatArg;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.nullValue;
+
+import java.util.Iterator;
+
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.core.commons.ensure.Assert;
+import org.apache.isis.core.commons.ensure.Ensure;
+import org.apache.isis.core.commons.ensure.IsisAssertException;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapterFactory;
+import org.apache.isis.core.metamodel.adapter.ResolveState;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManagerAware;
+import org.apache.isis.core.metamodel.adapter.oid.AggregatedOid;
+import org.apache.isis.core.metamodel.adapter.oid.CollectionOid;
+import org.apache.isis.core.metamodel.adapter.oid.Oid;
+import org.apache.isis.core.metamodel.adapter.oid.OidMarshaller;
+import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+import org.apache.isis.core.metamodel.adapter.oid.TypedOid;
+import org.apache.isis.core.metamodel.adapter.version.Version;
+import org.apache.isis.core.metamodel.facets.accessor.PropertyOrCollectionAccessorFacet;
+import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
+import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacetUtils;
+import org.apache.isis.core.metamodel.facets.object.aggregated.ParentedFacet;
+import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
+import org.apache.isis.core.metamodel.facets.typeof.ElementSpecificationProviderFromTypeOfFacet;
+import org.apache.isis.core.metamodel.facets.typeof.TypeOfFacet;
+import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
+import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpi;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+import org.apache.isis.runtimes.dflt.runtime.system.persistence.AdapterManagerSpi;
+import org.apache.isis.runtimes.dflt.runtime.system.persistence.OidGenerator;
+import org.apache.isis.runtimes.dflt.runtime.system.persistence.PersistenceSession;
+import org.apache.log4j.Logger;
+
+public class AdapterManagerDefault implements AdapterManagerSpi {
+
+    private static final Logger LOG = Logger.getLogger(AdapterManagerDefault.class);
+
+    protected final PojoAdapterHashMap pojoAdapterMap = new PojoAdapterHashMap();
+    protected final OidAdapterHashMap oidAdapterMap = new OidAdapterHashMap();
+
+    private final PojoRecreator pojoRecreator;
+
+
+    // //////////////////////////////////////////////////////////////////
+    // constructor
+    // //////////////////////////////////////////////////////////////////
+
+    /**
+     * For object store implementations (eg JDO) that do not provide any mechanism
+     * to allow transient objects to be reattached; can instead provide a
+     * {@link PojoRecreator} implementation that is injected into the Adapter Manager.
+     * 
+     * @see http://www.datanucleus.org/servlet/forum/viewthread_thread,7238_lastpage,yes#35976
+     */
+    public AdapterManagerDefault(PojoRecreator pojoRecreator) {
+        this.pojoRecreator = pojoRecreator;
+    }
+
+    // //////////////////////////////////////////////////////////////////
+    // open, close
+    // //////////////////////////////////////////////////////////////////
+
+    @Override
+    public void open() {
+        oidAdapterMap.open();
+        pojoAdapterMap.open();
+    }
+
+    @Override
+    public void close() {
+        oidAdapterMap.close();
+        pojoAdapterMap.close();
+    }
+
+    // //////////////////////////////////////////////////////////////////
+    // reset
+    // //////////////////////////////////////////////////////////////////
+
+    @Override
+    public void reset() {
+        oidAdapterMap.reset();
+        pojoAdapterMap.reset();
+    }
+
+    // //////////////////////////////////////////////////////////////////
+    // Iterable
+    // //////////////////////////////////////////////////////////////////
+
+    @Override
+    public Iterator<ObjectAdapter> iterator() {
+        return pojoAdapterMap.iterator();
+    }
+
+
+    
+
+    // //////////////////////////////////////////////////////////////////
+    // Adapter lookup
+    // //////////////////////////////////////////////////////////////////
+
+    @Override
+    public ObjectAdapter getAdapterFor(final Object pojo) {
+        ensureThatArg(pojo, is(notNullValue()));
+
+        return pojoAdapterMap.getAdapter(pojo);
+    }
+
+    @Override
+    public ObjectAdapter getAdapterFor(final Oid oid) {
+        ensureThatArg(oid, is(notNullValue()));
+        ensureMapsConsistent(oid);
+
+        return oidAdapterMap.getAdapter(oid);
+    }
+
+    
+    // //////////////////////////////////////////////////////////////////
+    // Adapter lookup/creation
+    // //////////////////////////////////////////////////////////////////
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ObjectAdapter adapterFor(final Object pojo) {
+
+        final ObjectAdapter existingOrValueAdapter = existingOrValueAdapter(pojo);
+        if(existingOrValueAdapter != null) {
+            return existingOrValueAdapter;
+        }
+        
+        final ObjectAdapter newAdapter = createTransientRootAdapter(pojo);
+        
+        return mapAndInjectServices(newAdapter);
+    }
+
+    private ObjectAdapter existingOrValueAdapter(Object pojo) {
+
+        // attempt to locate adapter for the pojo
+        final ObjectAdapter adapter = getAdapterFor(pojo);
+        if (adapter != null) {
+            return adapter;
+        }
+        
+        // pojo may have been lazily loaded by object store, but we haven't yet seen it
+        final ObjectAdapter lazilyLoadedAdapter = pojoRecreator.lazilyLoaded(pojo);
+        if(lazilyLoadedAdapter != null) {
+            return lazilyLoadedAdapter;
+        }
+        
+        
+        // need to create (and possibly map) the adapter.
+        final ObjectSpecification objSpec = getSpecificationLoader().loadSpecification(pojo.getClass());
+        
+        // we create value facets as standalone (so not added to maps)
+        if (objSpec.containsFacet(ValueFacet.class)) {
+            ObjectAdapter valueAdapter = createStandaloneAdapterAndSetResolveState(pojo);
+            return valueAdapter;
+        }
+        
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ObjectAdapter adapterFor(final Object pojo, final ObjectAdapter parentAdapter) {
+        
+        Ensure.ensureThatArg(parentAdapter, is(not(nullValue())));
+        
+        final ObjectAdapter existingOrValueAdapter = existingOrValueAdapter(pojo);
+        if(existingOrValueAdapter != null) {
+            return existingOrValueAdapter;
+        }
+        
+        final ObjectSpecification objSpec = getSpecificationLoader().loadSpecification(pojo.getClass());
+        
+        final ObjectAdapter newAdapter;
+        if(isAggregated(objSpec)) {
+            final AggregatedOid aggregatedOid = getOidGenerator().createAggregateOid(pojo, parentAdapter);
+            newAdapter = createAggregatedAdapter(pojo, aggregatedOid);
+        } else {
+            newAdapter = createTransientRootAdapter(pojo);
+        }
+        
+        return mapAndInjectServices(newAdapter);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ObjectAdapter adapterFor(final Object pojo, final ObjectAdapter parentAdapter, final OneToManyAssociation collection) {
+        
+        Ensure.ensureThatArg(parentAdapter, is(not(nullValue())));
+        Ensure.ensureThatArg(collection, is(not(nullValue())));
+        
+        final ObjectAdapter existingOrValueAdapter = existingOrValueAdapter(pojo);
+        if(existingOrValueAdapter != null) {
+            return existingOrValueAdapter;
+        }
+        
+        // the List, Set etc. instance gets wrapped in its own adapter
+        final ObjectAdapter newAdapter = createCollectionAdapter(pojo, parentAdapter, collection);
+        
+        return mapAndInjectServices(newAdapter);
+    }
+
+    
+    /**
+     * Creates an {@link ObjectAdapter adapter} to represent a collection
+     * of the parent.
+     * 
+     * <p>
+     * The returned adapter will have a {@link CollectionOid}; its version 
+     * and its persistence are the same as its owning parent.
+     * 
+     * <p>
+     * Should only be called if the pojo is known not to be
+     * {@link #getAdapterFor(Object) mapped}.
+     */
+    private ObjectAdapter createCollectionAdapter(final Object pojo, final ObjectAdapter parentAdapter, final OneToManyAssociation otma) {
+
+        ensureMapsConsistent(parentAdapter);
+        Assert.assertNotNull(pojo);
+
+        final Oid parentOid = parentAdapter.getOid();
+
+        // persistence of collection follows the parent
+        final CollectionOid collectionOid = new CollectionOid((TypedOid) parentOid, otma);
+        final ObjectAdapter collectionAdapter = createCollectionAdapterAndInferResolveState(pojo, collectionOid);
+
+        // we copy over the type onto the adapter itself
+        // [not sure why this is really needed, surely we have enough info in
+        // the adapter
+        // to look this up on the fly?]
+        final TypeOfFacet facet = otma.getFacet(TypeOfFacet.class);
+        collectionAdapter.setElementSpecificationProvider(ElementSpecificationProviderFromTypeOfFacet.createFrom(facet));
+
+        return collectionAdapter;
+    }
+
+    private static boolean isAggregated(final ObjectSpecification objSpec) {
+        return objSpec.containsFacet(ParentedFacet.class);
+    }
+
+    
+    // //////////////////////////////////////////////////////////////////
+    // Recreate adapter
+    // //////////////////////////////////////////////////////////////////
+
+    @Override
+    public ObjectAdapter adapterFor(final TypedOid typedOid) {
+        return adapterFor(typedOid, ConcurrencyChecking.NO_CHECK);
+    }
+
+
+    @Override
+    public ObjectAdapter adapterFor(final TypedOid typedOid, final ConcurrencyChecking concurrencyChecking) {
+
+        // attempt to locate adapter for the Oid
+        ObjectAdapter adapter = getAdapterFor(typedOid);
+        if (adapter != null) {
+            return adapter;
+        } 
+        
+        final Object pojo = pojoRecreator.recreatePojo(typedOid);
+        adapter = mapRecreatedPojo(typedOid, pojo);
+        
+        final Oid adapterOid = adapter.getOid();
+        if(adapterOid instanceof RootOid) {
+            final RootOid recreatedOid = (RootOid) adapterOid;
+            final RootOid originalOid = (RootOid) typedOid;
+            try {
+                if(concurrencyChecking == ConcurrencyChecking.CHECK) {
+                    recreatedOid.checkLock(getAuthenticationSession().getUserName(), originalOid);
+                }
+            } finally {
+                originalOid.setVersion(recreatedOid.getVersion());
+            }
+        }
+        return adapter;
+    }
+
+    
+
+    @Override
+    public void remapRecreatedPojo(ObjectAdapter adapter, final Object pojo) {
+        removeAdapter(adapter);
+        adapter.replacePojo(pojo);
+        mapAndInjectServices(adapter);
+    }
+
+
+    @Override
+    public ObjectAdapter mapRecreatedPojo(final Oid oid, final Object recreatedPojo) {
+
+        // attempt to locate adapter for the pojo
+        // REVIEW: this check is possibly redundant because the pojo will most likely 
+        // have just been instantiated, so won't yet be in any maps
+        final ObjectAdapter adapterLookedUpByPojo = getAdapterFor(recreatedPojo);
+        if (adapterLookedUpByPojo != null) {
+            return adapterLookedUpByPojo;
+        }
+
+        // attempt to locate adapter for the Oid
+        final ObjectAdapter adapterLookedUpByOid = getAdapterFor(oid);
+        if (adapterLookedUpByOid != null) {
+            return adapterLookedUpByOid;
+        }
+
+        final ObjectAdapter createdAdapter = createRootOrAggregatedAdapter(oid, recreatedPojo);
+        return mapAndInjectServices(createdAdapter);
+    }
+
+    private ObjectAdapter createRootOrAggregatedAdapter(final Oid oid, final Object pojo) {
+        final ObjectAdapter createdAdapter;
+        if(oid instanceof RootOid) {
+            final RootOid rootOid = (RootOid) oid;
+            createdAdapter = createRootAdapterAndInferResolveState(pojo, rootOid);
+        } else if (oid instanceof CollectionOid){
+            final CollectionOid collectionOid = (CollectionOid) oid;
+            createdAdapter = createCollectionAdapterAndInferResolveState(pojo, collectionOid);
+        } else {
+            final AggregatedOid aggregatedOid = (AggregatedOid) oid;
+            createdAdapter = createAggregatedAdapter(pojo, aggregatedOid);
+        }
+        return createdAdapter;
+    }
+
+
+    // //////////////////////////////////////////////////////////////////
+    // adapter deletion
+    // //////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Removes the specified object from both the identity-adapter map, and the
+     * pojo-adapter map.
+     * 
+     * <p>
+     * This indicates that the object is no longer in use, and therefore that no
+     * objects exists within the system.
+     * 
+     * <p>
+     * If an {@link ObjectAdapter adapter} is removed while its pojo still is
+     * referenced then a subsequent interaction of that pojo will create a
+     * different {@link ObjectAdapter adapter}, in a
+     * {@link ResolveState#TRANSIENT transient} state.
+     * 
+     * <p>
+     * TODO: should do a cascade remove of any aggregated objects.
+     */
+    @Override
+    public void removeAdapter(final ObjectAdapter adapter) {
+        ensureMapsConsistent(adapter);
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("removing adapter: " + adapter);
+        }
+
+        unmap(adapter);
+    }
+
+    // //////////////////////////////////////////////////////////////////
+    // Persist API
+    // //////////////////////////////////////////////////////////////////
+
+    /**
+     * {@inheritDoc}
+     * 
+     * <p>
+     * Note that there is no management of {@link Version}s here. That is
+     * because the {@link PersistenceSession} is expected to manage this.
+     * 
+     * @param hintRootOid - allow a different persistent root oid to be provided.
+     */
+    @Override
+    public void remapAsPersistent(final ObjectAdapter adapter, RootOid hintRootOid) {
+        
+        final ObjectAdapter rootAdapter = adapter.getAggregateRoot();  // REVIEW: think this is redundant; would seem this method is only ever called for roots anyway.
+        final RootOid transientRootOid = (RootOid) rootAdapter.getOid();
+
+        Ensure.ensureThatArg(rootAdapter.isTransient(), is(true), "root adapter should be transient; oid:" + transientRootOid);
+        Ensure.ensureThatArg(transientRootOid.isTransient(), is(true), "root adapter's OID should be transient; oid:" + transientRootOid);
+        
+        final RootAndCollectionAdapters rootAndCollectionAdapters = new RootAndCollectionAdapters(adapter, this);
+        
+        
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("remapAsPersistent: " + transientRootOid);
+        }
+        
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("removing root adapter from oid map");
+        }
+        
+        boolean removed = oidAdapterMap.remove(transientRootOid);
+        if (!removed) {
+            LOG.warn("could not remove oid: " + transientRootOid);
+            // should we fail here with a more serious error?
+        }
+        
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("removing collection adapter(s) from oid map");
+        }
+        for (final ObjectAdapter collectionAdapter : rootAndCollectionAdapters) {
+            final Oid collectionOid = collectionAdapter.getOid();
+            removed = oidAdapterMap.remove(collectionOid);
+            if (!removed) {
+                LOG.warn("could not remove collectionOid: " + collectionOid);
+                // should we fail here with a more serious error?
+            }
+        }
+        
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("updating the Oid");
+        }
+        
+        // intended for testing (bit nasty)
+        final RootOid persistedRootOid;
+        if(hintRootOid != null) {
+            if(hintRootOid.isTransient()) {
+                throw new IsisAssertException("hintRootOid must be persistent");
+            }
+            final ObjectSpecId hintRootOidObjectSpecId = hintRootOid.getObjectSpecId();
+            final ObjectSpecId adapterObjectSpecId = adapter.getSpecification().getSpecId();
+            if(!hintRootOidObjectSpecId.equals(adapterObjectSpecId)) {
+                throw new IsisAssertException("hintRootOid's objectType must be same as that of adapter " +
+                		"(was: '" + hintRootOidObjectSpecId + "'; adapter's is " + adapterObjectSpecId + "'");
+            }
+            // ok
+            persistedRootOid = hintRootOid;
+        } else {
+            // normal flow - delegate to OidGenerator to obtain a persistent root oid
+            persistedRootOid = getOidGenerator().createPersistent(adapter.getObject(), transientRootOid);
+        }
+        
+        // associate root adapter with the new Oid, and remap
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("replacing Oid for root adapter and re-adding into maps; oid is now: " + persistedRootOid.enString(getOidMarshaller()) + " (was: " + transientRootOid.enString(getOidMarshaller()) + ")");
+        }
+        adapter.replaceOid(persistedRootOid);
+        oidAdapterMap.add(persistedRootOid, adapter);
+        
+        // associate the collection adapters with new Oids, and re-map
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("replacing Oids for collection adapter(s) and re-adding into maps");
+        }
+        for (final ObjectAdapter collectionAdapter : rootAndCollectionAdapters) {
+            final CollectionOid previousCollectionOid = (CollectionOid) collectionAdapter.getOid();
+            final CollectionOid persistedCollectionOid = previousCollectionOid.asPersistent(persistedRootOid);
+            oidAdapterMap.add(persistedCollectionOid, collectionAdapter);
+        }
+
+        
+        // some object store implementations may replace collection instances (eg ORM may replace with a cglib-enhanced
+        // proxy equivalent.  So, ensure that the collection adapters still wrap the correct pojos.
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("synchronizing collection pojos, remapping in pojo map if required");
+        }
+        for (final OneToManyAssociation otma : rootAndCollectionAdapters.getCollections()) {
+            final ObjectAdapter collectionAdapter = rootAndCollectionAdapters.getCollectionAdapter(otma);
+        
+            final Object collectionPojoWrappedByAdapter = collectionAdapter.getObject();
+            final Object collectionPojoActuallyOnPojo = getCollectionPojo(otma, adapter);
+        
+            if (collectionPojoActuallyOnPojo != collectionPojoWrappedByAdapter) {
+                pojoAdapterMap.remove(collectionAdapter);
+                collectionAdapter.replacePojo(collectionPojoActuallyOnPojo);
+                pojoAdapterMap.add(collectionPojoActuallyOnPojo, collectionAdapter);
+            }
+        }
+
+        remapContainedAggregatedObject(adapter, persistedRootOid);
+        
+        // update the adapter's state
+        adapter.changeState(ResolveState.RESOLVED);
+        
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("made persistent " + adapter + "; was " + transientRootOid);
+        }
+    }
+
+    private void remapContainedAggregatedObject(final ObjectAdapter adapter, final RootOid persistedRootOid) {
+        for (final ObjectAssociation association: adapter.getSpecification().getAssociations()) {
+            if (association.isOneToManyAssociation() && !association.isNotPersisted()) {
+                final ObjectAdapter collection = association.get(adapter);
+                final CollectionFacet facet = CollectionFacetUtils.getCollectionFacetFromSpec(collection);
+                for (final ObjectAdapter element : facet.iterable(collection)) {
+                   remapAggregatedObject(element, persistedRootOid);
+                }
+                
+            } else if (association.getSpecification().isParented()) {
+                final ObjectAdapter referencedAdapter = association.get(adapter);
+    
+                if(referencedAdapter == null) {
+                    continue;
+                }
+                remapAggregatedObject(referencedAdapter, persistedRootOid);
+            }
+        }
+    }
+
+    private void remapAggregatedObject(final ObjectAdapter adapter, final RootOid persistedRootOid) {
+        final Oid oid = adapter.getOid();
+        if (!(oid instanceof AggregatedOid) || !oid.isTransient()) {
+                return;
+        }
+        AggregatedOid aoid = (AggregatedOid) oid;
+        AggregatedOid childOid = new AggregatedOid(aoid.getObjectSpecId(), persistedRootOid, aoid.getLocalId());
+        adapter.replaceOid(childOid);
+        
+        remapContainedAggregatedObject(adapter, persistedRootOid);
+    }
+
+	private static Object getCollectionPojo(final OneToManyAssociation association, final ObjectAdapter ownerAdapter) {
+        final PropertyOrCollectionAccessorFacet accessor = association.getFacet(PropertyOrCollectionAccessorFacet.class);
+        return accessor.getProperty(ownerAdapter);
+    }
+
+
+    // ///////////////////////////////////////////////////////////////////////////
+    // Helpers
+    // ///////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Creates a new transient root {@link ObjectAdapter adapter} for the supplied domain
+     * object.
+     * 
+     * <p>
+     * Has <tt>protected</tt> visibility just so can be used by subclasses if required.
+     */
+    protected final ObjectAdapter createTransientRootAdapter(final Object pojo) {
+        final RootOid transientRootOid = getOidGenerator().createTransientOid(pojo);
+        return createRootAdapterAndInferResolveState(pojo, transientRootOid);
+    }
+
+    /**
+     * Creates a {@link ObjectAdapter adapter} with no {@link Oid}.
+     *
+     * <p>
+     * The {@link ResolveState} state will be {@link ResolveState#VALUE}.
+     * Standalone adapters are never {@link #mapAndInjectServices(ObjectAdapter) mapped}
+     * (they have no {@link Oid}, after all).
+     * 
+     * <p>
+     * Should only be called if the pojo is known not to be
+     * {@link #getAdapterFor(Object) mapped}, and for immutable value types
+     * referenced.
+     */
+    private ObjectAdapter createStandaloneAdapterAndSetResolveState(final Object pojo) {
+        final ObjectAdapter adapter = getObjectAdapterFactory().createAdapter(pojo, null, this);
+        adapter.changeState(ResolveState.VALUE);
+        return adapter;
+    }
+
+    /**
+     * Creates (but does not {@link #mapAndInjectServices(ObjectAdapter) map}) a new 
+     * root {@link ObjectAdapter adapter} for the supplied domain object, and 
+     * sets its {@link ResolveState} based on the {@link Oid}.
+     * 
+     * <p>
+     * The {@link ResolveState} state will be:
+     * <ul>
+     * <li> {@link ResolveState#TRANSIENT} if the {@link Oid} is
+     * {@link Oid#isTransient() transient}.
+     * <li> {@link ResolveState#GHOST} if the {@link Oid} is persistent (not
+     * {@link Oid#isTransient() transient}).
+     * </ul>
+     * 
+     * @see #createStandaloneAdapterAndSetResolveState(Object)
+     * @see #createCollectionAdapterAndInferResolveState(Object, CollectionOid)
+     */
+    private ObjectAdapter createRootAdapterAndInferResolveState(final Object pojo, RootOid rootOid) {
+        Ensure.ensureThatArg(rootOid, is(not(nullValue())));
+        final ObjectAdapter rootAdapter = getObjectAdapterFactory().createAdapter(pojo, rootOid, this);
+        rootAdapter.changeState(rootOid.isTransient() ? ResolveState.TRANSIENT : ResolveState.GHOST);
+        doPostCreateRootAdapter(rootAdapter);
+        return rootAdapter;
+    }
+
+    /**
+     * Hook method for objectstores to register the newly created root-adapter.
+     * 
+     * <p>
+     * For example, the JDO DataNucleus object store uses this to attach the pojo
+     * into its persistence context.  This enables dirty tracking and lazy loading of the
+     * pojo.
+     */
+    protected void doPostCreateRootAdapter(ObjectAdapter rootAdapter) {
+        
+    }
+
+    private ObjectAdapter createCollectionAdapterAndInferResolveState(final Object pojo, CollectionOid collectionOid) {
+        Ensure.ensureThatArg(collectionOid, is(not(nullValue())));
+        final ObjectAdapter collectionAdapter = getObjectAdapterFactory().createAdapter(pojo, collectionOid, this);
+        collectionAdapter.changeState(collectionOid.isTransient() ? ResolveState.TRANSIENT : ResolveState.GHOST);
+        return collectionAdapter;
+    }
+
+    private ObjectAdapter createAggregatedAdapter(final Object pojo, AggregatedOid aggregatedOid) {
+        Ensure.ensureThatArg(aggregatedOid, is(not(nullValue())));
+        final ObjectAdapter aggregatedAdapter = getObjectAdapterFactory().createAdapter(pojo, aggregatedOid, this);
+        // aggregated; nothing to do, since transient state determined by its parent.
+        return aggregatedAdapter;
+    }
+
+    // //////////////////////////////////////////////////////////////////////////
+    // Helpers: map & unmap
+    // //////////////////////////////////////////////////////////////////////////
+
+    private ObjectAdapter mapAndInjectServices(final ObjectAdapter adapter) {
+        // since the whole point of this method is to map an adapter that's just been created.
+        // so we *don't* call ensureMapsConsistent(adapter); 
+
+        Assert.assertNotNull(adapter);
+        final Object pojo = adapter.getObject();
+        Assert.assertFalse("POJO Map already contains object", pojo, pojoAdapterMap.containsPojo(pojo));
+
+        if (LOG.isDebugEnabled()) {
+            // don't interact with the underlying object because may be a ghost
+            // and would trigger a resolve
+            // don't call toString() on adapter because calls hashCode on
+            // underlying object, may also trigger a resolve.
+            LOG.debug("adding identity for adapter with oid=" + adapter.getOid());
+        }
+
+        // value adapters are not mapped (but all others - root and aggregated adapters - are)
+        if (adapter.isValue()) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("not mapping value adapter");
+            }
+            getServicesInjector().injectServicesInto(pojo);
+            return adapter;
+        }
+
+        // add all aggregated collections
+        final ObjectSpecification objSpec = adapter.getSpecification();
+        if (!adapter.isParented() || adapter.isParented() && !objSpec.isImmutable()) {
+            pojoAdapterMap.add(pojo, adapter);
+        }
+
+        // order is important - add to pojo map first, then identity map
+        oidAdapterMap.add(adapter.getOid(), adapter);
+
+        // must inject after mapping, otherwise infinite loop
+        getServicesInjector().injectServicesInto(pojo);
+
+        return adapter;
+    }
+
+    private void unmap(final ObjectAdapter adapter) {
+        ensureMapsConsistent(adapter);
+
+        final Oid oid = adapter.getOid();
+        if (oid != null) {
+            oidAdapterMap.remove(oid);
+        }
+        pojoAdapterMap.remove(adapter);
+    }
+
+    // //////////////////////////////////////////////////////////////////////////
+    // Helpers: ensure invariants
+    // //////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Fail early if any problems.
+     */
+    private void ensureMapsConsistent(final ObjectAdapter adapter) {
+        if (adapter.isValue()) {
+            return;
+        }
+        if (adapter.isParented()) {
+            return;
+        }
+        ensurePojoAdapterMapConsistent(adapter);
+        ensureOidAdapterMapConsistent(adapter);
+    }
+
+    /**
+     * Fail early if any problems.
+     */
+    private void ensureMapsConsistent(final Oid oid) {
+        ensureThatArg(oid, is(notNullValue()));
+
+        final ObjectAdapter adapter = oidAdapterMap.getAdapter(oid);
+        if (adapter == null) {
+            return;
+        }
+        ensureOidAdapterMapConsistent(adapter);
+        ensurePojoAdapterMapConsistent(adapter);
+    }
+
+    private void ensurePojoAdapterMapConsistent(final ObjectAdapter adapter) {
+        final Object adapterPojo = adapter.getObject();
+        final ObjectAdapter adapterAccordingToPojoAdapterMap = pojoAdapterMap.getAdapter(adapterPojo);
+        ensureThatArg(adapter, is(adapterAccordingToPojoAdapterMap), "mismatch in PojoAdapterMap: adapter's Pojo: " + adapterPojo + ", \n" + "provided adapter: " + adapter + "; \n" + " but map's adapter was : " + adapterAccordingToPojoAdapterMap);
+    }
+
+    private void ensureOidAdapterMapConsistent(final ObjectAdapter adapter) {
+        final Oid adapterOid = adapter.getOid();
+        final ObjectAdapter adapterAccordingToOidAdapterMap = oidAdapterMap.getAdapter(adapterOid);
+        ensureThatArg(adapter, is(adapterAccordingToOidAdapterMap), "mismatch in OidAdapter map: " + "adapter's Oid: " + adapterOid + ", " + "provided adapter: " + adapter + "; " + "map's adapter: " + adapterAccordingToOidAdapterMap);
+    }
+
+    // //////////////////////////////////////////////////////////////////
+    // debug
+    // //////////////////////////////////////////////////////////////////
+
+    @Override
+    public String debugTitle() {
+        return "Identity map (adapter manager)";
+    }
+
+    @Override
+    public void debugData(final DebugBuilder debug) {
+        debug.appendTitle(pojoAdapterMap.debugTitle());
+        pojoAdapterMap.debugData(debug);
+        debug.appendln();
+
+        debug.appendTitle(oidAdapterMap.debugTitle());
+        oidAdapterMap.debugData(debug);
+
+    }
+
+    
+    // //////////////////////////////////////////////////////////////////////////
+    // Injectable
+    // //////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public void injectInto(final Object candidate) {
+        if (AdapterManagerAware.class.isAssignableFrom(candidate.getClass())) {
+            final AdapterManagerAware cast = AdapterManagerAware.class.cast(candidate);
+            cast.setAdapterManager(this);
+        }
+    }
+
+    
+    // /////////////////////////////////////////////////////////////////
+    // Dependencies (from context)
+    // /////////////////////////////////////////////////////////////////
+
+    protected OidMarshaller getOidMarshaller() {
+		return IsisContext.getOidMarshaller();
+	}
+
+    public OidGenerator getOidGenerator() {
+        return IsisContext.getPersistenceSession().getOidGenerator();
+    }
+
+    protected SpecificationLoaderSpi getSpecificationLoader() {
+        return IsisContext.getSpecificationLoader();
+    }
+
+    protected ObjectAdapterFactory getObjectAdapterFactory() {
+        return getPersistenceSession().getObjectAdapterFactory();
+    }
+
+    protected PersistenceSession getPersistenceSession() {
+        return IsisContext.getPersistenceSession();
+    }
+
+    protected ServicesInjector getServicesInjector() {
+        return IsisContext.getPersistenceSession().getServicesInjector();
+    }
+
+    protected AuthenticationSession getAuthenticationSession() {
+        return IsisContext.getAuthenticationSession();
+    }
+    
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/dbb64345/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adaptermanager/AdapterUtils.java
----------------------------------------------------------------------
diff --git a/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adaptermanager/AdapterUtils.java b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adaptermanager/AdapterUtils.java
new file mode 100644
index 0000000..da432c5
--- /dev/null
+++ b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adaptermanager/AdapterUtils.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.runtimes.dflt.runtime.persistence.adaptermanager;
+
+import org.apache.isis.core.commons.exceptions.UnknownTypeException;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
+import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacetUtils;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpi;
+import org.apache.isis.runtimes.dflt.runtime.system.persistence.AdapterManagerSpi;
+
+public final class AdapterUtils {
+    private AdapterUtils() {
+    }
+
+    public static ObjectAdapter createAdapter(final Class<?> type, final Object object, final AdapterManagerSpi adapterManager, final SpecificationLoaderSpi specificationLoader) {
+        final ObjectSpecification specification = specificationLoader.loadSpecification(type);
+        if (specification.isNotCollection()) {
+            return adapterManager.adapterFor(object);
+        } else {
+            throw new UnknownTypeException("not an object, is this a collection?");
+        }
+    }
+
+    public static Object[] getCollectionAsObjectArray(final Object option, final ObjectSpecification spec, final AdapterManagerSpi adapterManager) {
+        final ObjectAdapter collection = adapterManager.adapterFor(option);
+        final CollectionFacet facet = CollectionFacetUtils.getCollectionFacetFromSpec(collection);
+        final Object[] optionArray = new Object[facet.size(collection)];
+        int j = 0;
+        for (final ObjectAdapter adapter : facet.iterable(collection)) {
+            optionArray[j++] = adapter.getObject();
+        }
+        return optionArray;
+    }
+
+    public static Object domainObject(final ObjectAdapter inObject) {
+        return inObject == null ? null : inObject.getObject();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/dbb64345/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adaptermanager/ObjectToAdapterTransformer.java
----------------------------------------------------------------------
diff --git a/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adaptermanager/ObjectToAdapterTransformer.java b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adaptermanager/ObjectToAdapterTransformer.java
new file mode 100644
index 0000000..789832f
--- /dev/null
+++ b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adaptermanager/ObjectToAdapterTransformer.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.runtimes.dflt.runtime.persistence.adaptermanager;
+
+import org.apache.commons.collections.Transformer;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+import org.apache.isis.runtimes.dflt.runtime.system.persistence.PersistenceSession;
+
+/**
+ * Uses the Commons Collection API to transform {@link Object}s into
+ * {@link ObjectAdapter} adapters.
+ * 
+ */
+public final class ObjectToAdapterTransformer implements Transformer {
+
+    public ObjectToAdapterTransformer() {
+    }
+
+    @Override
+    public Object transform(final Object object) {
+        return getAdapterManager().adapterFor(object);
+    }
+
+    // //////////////////////////////////////////////////////////////////
+    // Dependencies (from context)
+    // //////////////////////////////////////////////////////////////////
+
+    protected AdapterManager getAdapterManager() {
+        return getPersistenceSession().getAdapterManager();
+    }
+
+    protected PersistenceSession getPersistenceSession() {
+        return IsisContext.getPersistenceSession();
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/dbb64345/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adaptermanager/OidAdapterHashMap.java
----------------------------------------------------------------------
diff --git a/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adaptermanager/OidAdapterHashMap.java b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adaptermanager/OidAdapterHashMap.java
new file mode 100644
index 0000000..282945e
--- /dev/null
+++ b/framework/core/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/persistence/adaptermanager/OidAdapterHashMap.java
@@ -0,0 +1,154 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.runtimes.dflt.runtime.persistence.adaptermanager;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import com.google.common.collect.Maps;
+
+import org.apache.log4j.Logger;
+
+import org.apache.isis.core.commons.components.Resettable;
+import org.apache.isis.core.commons.components.SessionScopedComponent;
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.core.commons.debug.DebuggableWithTitle;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.oid.Oid;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+
+/**
+ * A map of the objects' identities and the adapters' of the objects.
+ */
+public class OidAdapterHashMap implements DebuggableWithTitle, Iterable<Oid>, SessionScopedComponent, Resettable {
+
+    private static final Logger LOG = Logger.getLogger(OidAdapterHashMap.class);
+    public static final int DEFAULT_OID_ADAPTER_MAP_SIZE = 100;
+
+    private final Map<Oid, ObjectAdapter> adapterByOidMap = Maps.newHashMapWithExpectedSize(DEFAULT_OID_ADAPTER_MAP_SIZE);
+
+
+    // ///////////////////////////////////////////////////////
+    // open, close
+    // ///////////////////////////////////////////////////////
+
+    @Override
+    public void open() {
+        // nothing to do
+    }
+
+    @Override
+    public void close() {
+        LOG.debug("close");
+        adapterByOidMap.clear();
+    }
+
+    // ///////////////////////////////////////////////////////
+    // reset
+    // ///////////////////////////////////////////////////////
+
+    /**
+     * Removes all {@link ObjectSpecification#isService() non-service} adapters.
+     */
+    @Override
+    public void reset() {
+        LOG.debug("reset");
+        for (final Iterator<Map.Entry<Oid, ObjectAdapter>> iterator = adapterByOidMap.entrySet().iterator(); iterator.hasNext();) {
+            final Map.Entry<Oid, ObjectAdapter> entry = iterator.next();
+            final ObjectAdapter adapter = entry.getValue();
+            if (!adapter.getSpecification().isService()) {
+                iterator.remove();
+            }
+        }
+    }
+
+    // ///////////////////////////////////////////////////////
+    // add, remove
+    // ///////////////////////////////////////////////////////
+
+    /**
+     * Add an adapter for a given oid
+     */
+    public void add(final Oid oid, final ObjectAdapter adapter) {
+
+        adapterByOidMap.put(oid, adapter);
+        // log at end so that if toString needs adapters they're in maps.
+        if (LOG.isDebugEnabled()) {
+            // do not call toString() on adapter because would call hashCode on
+            // the pojo,
+            // which for Hibernate PersistentCollections would trigger a
+            // resolve.
+            LOG.debug("add oid: " + oid + " ; oid.hashCode: + #" + Long.toHexString(oid.hashCode()) + " ; adapter.hashCode(): #" + Long.toHexString(adapter.hashCode()));
+        }
+    }
+
+    /**
+     * Remove the adapter for the given oid
+     * 
+     * @return <tt>true</tt> if an adapter was removed.
+     */
+    public boolean remove(final Oid oid) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("remove oid: " + oid);
+        }
+        return adapterByOidMap.remove(oid) != null;
+    }
+
+
+    /**
+     * Get the adapter identified by the specified OID.
+     */
+    public ObjectAdapter getAdapter(final Oid oid) {
+        return adapterByOidMap.get(oid);
+    }
+
+    // ///////////////////////////////////////////////////////
+    // iterator
+    // ///////////////////////////////////////////////////////
+
+    @Override
+    public Iterator<Oid> iterator() {
+        return adapterByOidMap.keySet().iterator();
+    }
+
+    // ///////////////////////////////////////////////////////
+    // debugging
+    // ///////////////////////////////////////////////////////
+
+    @Override
+    public String debugTitle() {
+        return "Identity adapter map";
+    }
+
+    @Override
+    public void debugData(final DebugBuilder debug) {
+        int count = 1;
+        for (final Oid oid : this) {
+            final ObjectAdapter adapter = getAdapter(oid);
+            debug.append(count++, 5);
+            debug.append(" '");
+            debug.append(oid.toString(), 15);
+            debug.append("'    ");
+            debug.appendln(adapter != null ? adapter.toString() : "(MISSING OBJECT ?!)");
+        }
+    }
+
+
+}