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 ?!)");
+ }
+ }
+
+
+}