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 17:59:48 UTC
[47/52] [partial] ISIS-188: more reorganizing of artifacts into
physical directories.
http://git-wip-us.apache.org/repos/asf/isis/blob/0861ed93/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/SqlObjectStore.java
----------------------------------------------------------------------
diff --git a/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/SqlObjectStore.java b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/SqlObjectStore.java
new file mode 100644
index 0000000..b3a9eec
--- /dev/null
+++ b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/SqlObjectStore.java
@@ -0,0 +1,507 @@
+/*
+ * 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.objectstores.sql;
+
+import java.util.List;
+import java.util.Vector;
+
+import com.google.common.collect.Lists;
+
+import org.apache.log4j.Logger;
+
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.core.commons.debug.DebugString;
+import org.apache.isis.core.commons.ensure.IsisAssertException;
+import org.apache.isis.core.commons.exceptions.IsisException;
+import org.apache.isis.core.commons.exceptions.NotYetImplementedException;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+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.RootOid;
+import org.apache.isis.core.metamodel.adapter.oid.RootOidDefault;
+import org.apache.isis.core.metamodel.adapter.oid.TypedOid;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.SpecificationLoader;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.runtimes.dflt.runtime.persistence.objectstore.ObjectStoreSpi;
+import org.apache.isis.runtimes.dflt.runtime.persistence.objectstore.transaction.CreateObjectCommand;
+import org.apache.isis.runtimes.dflt.runtime.persistence.objectstore.transaction.DestroyObjectCommand;
+import org.apache.isis.runtimes.dflt.runtime.persistence.objectstore.transaction.PersistenceCommand;
+import org.apache.isis.runtimes.dflt.runtime.persistence.objectstore.transaction.PersistenceCommandContext;
+import org.apache.isis.runtimes.dflt.runtime.persistence.objectstore.transaction.SaveObjectCommand;
+import org.apache.isis.runtimes.dflt.runtime.persistence.query.PersistenceQueryFindAllInstances;
+import org.apache.isis.runtimes.dflt.runtime.persistence.query.PersistenceQueryFindByPattern;
+import org.apache.isis.runtimes.dflt.runtime.persistence.query.PersistenceQueryFindByTitle;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+import org.apache.isis.runtimes.dflt.runtime.system.persistence.PersistenceQuery;
+import org.apache.isis.runtimes.dflt.runtime.system.transaction.IsisTransactionManager;
+import org.apache.isis.runtimes.dflt.runtime.system.transaction.MessageBroker;
+import org.apache.isis.runtimes.dflt.runtime.system.transaction.UpdateNotifier;
+
+public final class SqlObjectStore implements ObjectStoreSpi {
+
+ private static final String TABLE_NAME = "isis_admin_services";
+ // private static final String ID_COLUMN = "id";
+ // private static final String PRIMARYKEY_COLUMN = "pk_id";
+ public static final String BASE_NAME = "isis.persistor.sql";
+ private static final Logger LOG = Logger.getLogger(SqlObjectStore.class);
+ private DatabaseConnectorPool connectionPool;
+ private ObjectMappingLookup objectMappingLookup;
+ private boolean isInitialized;
+
+ @Override
+ public String name() {
+ return "SQL Object Store";
+ }
+
+ @Override
+ public void open() {
+ Sql.setMetaData(connectionPool.acquire().getMetaData());
+
+ if (!isInitialized) {
+ Defaults.initialise(BASE_NAME, IsisContext.getConfiguration());
+ Defaults.setPkIdLabel(Sql.identifier(Defaults.getPkIdLabel()));
+ Defaults.setIdColumn(Sql.identifier(Defaults.getIdColumn()));
+ }
+
+ final DebugBuilder debug = new DebugString();
+ connectionPool.debug(debug);
+ LOG.info("Database: " + debug);
+
+ objectMappingLookup.init();
+
+ final DatabaseConnector connector = connectionPool.acquire();
+ final String tableIdentifier = Sql.tableIdentifier(TABLE_NAME);
+ isInitialized = connector.hasColumn(tableIdentifier, Defaults.getPkIdLabel());
+ if (!isInitialized) {
+ if (connector.hasTable(tableIdentifier)) {
+ final StringBuffer sql = new StringBuffer();
+ sql.append("drop table ");
+ sql.append(tableIdentifier);
+ connector.update(sql.toString());
+ }
+ final StringBuffer sql = new StringBuffer();
+ sql.append("create table ");
+ sql.append(tableIdentifier);
+ sql.append(" (");
+ sql.append(Defaults.getPkIdLabel());
+ sql.append(" int, ");
+ sql.append(Defaults.getIdColumn());
+ sql.append(" varchar(255)");
+ sql.append(")");
+ connector.update(sql.toString());
+ }
+ }
+
+ @Override
+ public boolean isFixturesInstalled() {
+ return isInitialized;
+ }
+
+ @Override
+ public void registerService(final RootOid rootOid) {
+ final DatabaseConnector connector = connectionPool.acquire();
+
+ final StringBuffer sql = new StringBuffer();
+ sql.append("insert into ");
+ sql.append(Sql.tableIdentifier(TABLE_NAME));
+ sql.append(" (");
+ sql.append(Defaults.getPkIdLabel());
+ sql.append(", ");
+ sql.append(Defaults.getIdColumn());
+ sql.append(") values (?,?)");
+
+ final RootOidDefault sqlOid = (RootOidDefault) rootOid;
+ connector.addToQueryValues(sqlOid.getIdentifier());
+ connector.addToQueryValues(rootOid.getObjectSpecId().asString());
+
+ connector.insert(sql.toString());
+ connectionPool.release(connector);
+ }
+
+ @Override
+ public void reset() {
+ }
+
+ @Override
+ public void close() {
+ objectMappingLookup.shutdown();
+ connectionPool.shutdown();
+ }
+
+ @Override
+ public void startTransaction() {
+ executeSql(Defaults.START_TRANSACTION());
+ }
+
+ @Override
+ public void abortTransaction() {
+ executeSql(Defaults.ABORT_TRANSACTION());
+ }
+
+ @Override
+ public void endTransaction() {
+ executeSql(Defaults.COMMIT_TRANSACTION());
+ }
+
+ private void executeSql(String sql) {
+ final DatabaseConnector connector = connectionPool.acquire();
+ try {
+ connector.begin();
+ connector.update(sql);
+ connector.commit();
+ // connector.close();
+ } finally {
+ connectionPool.release(connector);
+ }
+ }
+
+ @Override
+ public CreateObjectCommand createCreateObjectCommand(final ObjectAdapter object) {
+ return new CreateObjectCommand() {
+ @Override
+ public void execute(final PersistenceCommandContext context) {
+ final DatabaseConnector connection = ((SqlExecutionContext) context).getConnection();
+ LOG.debug(" create object " + object);
+ final ObjectMapping mapping = objectMappingLookup.getMapping(object, connection);
+ mapping.createObject(connection, object);
+ }
+
+ @Override
+ public ObjectAdapter onAdapter() {
+ return object;
+ }
+
+ @Override
+ public String toString() {
+ return "CreateObjectCommand [object=" + object + "]";
+ }
+ };
+ }
+
+ @Override
+ public DestroyObjectCommand createDestroyObjectCommand(final ObjectAdapter object) {
+ return new DestroyObjectCommand() {
+ @Override
+ public void execute(final PersistenceCommandContext context) {
+ final DatabaseConnector connection = ((SqlExecutionContext) context).getConnection();
+ LOG.debug(" destroy object " + object);
+ final ObjectMapping mapping = objectMappingLookup.getMapping(object, connection);
+ mapping.destroyObject(connection, object);
+ }
+
+ @Override
+ public ObjectAdapter onAdapter() {
+ return object;
+ }
+
+ @Override
+ public String toString() {
+ return "DestroyObjectCommand [object=" + object + "]";
+ }
+ };
+ }
+
+ @Override
+ public SaveObjectCommand createSaveObjectCommand(final ObjectAdapter adapter) {
+ return new SaveObjectCommand() {
+ @Override
+ public void execute(final PersistenceCommandContext context) {
+ final DatabaseConnector connection = ((SqlExecutionContext) context).getConnection();
+ LOG.debug(" save object " + adapter.toString());
+
+ try {
+ final ObjectSpecification adapterSpec = adapter.getSpecification();
+ if (!adapterSpec.isParented()) {
+ saveRootAdapter(adapter, connection);
+ } else if(adapterSpec.isParentedOrFreeCollection()) {
+ saveParentedCollectionAdapter(adapter, connection);
+ } else {
+ throw new NotYetImplementedException("cannot yet persist aggregated objects: " + adapter.toString());
+ }
+ } finally {
+ connectionPool.release(connection);
+ }
+ }
+
+ private void saveRootAdapter(final ObjectAdapter adapter, final DatabaseConnector connection) {
+ final ObjectMapping mapping = objectMappingLookup.getMapping(adapter, connection);
+ mapping.save(connection, adapter);
+ }
+
+ private void saveParentedCollectionAdapter(final ObjectAdapter collectionAdapter, final DatabaseConnector connection) {
+ final ObjectAdapter parent = collectionAdapter.getAggregateRoot();
+ LOG.debug("change to internal collection being persisted through parent");
+
+ final Oid oid = collectionAdapter.getOid();
+ final CollectionOid collectionOid = (CollectionOid) oid;
+ if (!(oid instanceof CollectionOid)) {
+ throw new IsisAssertException("object should have a CollectionOid");
+ }
+
+ final ObjectMapping mapping = objectMappingLookup.getMapping(parent, connection);
+ if (! mapping.saveCollection(connection, parent, collectionOid.getName()) ) {
+ final ObjectMapping parentMapping = objectMappingLookup.getMapping(parent, connection);
+ parentMapping.save(connection, collectionAdapter);
+ }
+ }
+
+ @Override
+ public ObjectAdapter onAdapter() {
+ return adapter;
+ }
+
+ @Override
+ public String toString() {
+ return "SaveObjectCommand [object=" + adapter + "]";
+ }
+
+ };
+ }
+
+
+ @Override
+ public void debugData(final DebugBuilder debug) {
+ debug.appendln("initialised", isInitialized);
+ debug.appendln("connection pool", connectionPool);
+ debug.appendln("Database:");
+ debug.indent();
+ connectionPool.debug(debug);
+ debug.unindent();
+ objectMappingLookup.debugData(debug);
+ }
+
+ @Override
+ public String debugTitle() {
+ return null;
+ }
+
+ @Override
+ public void execute(final List<PersistenceCommand> commands) {
+ final DatabaseConnector connector = connectionPool.acquire();
+ connector.begin();
+
+ final IsisTransactionManager transactionManager = IsisContext.getTransactionManager();
+ final MessageBroker messageBroker = IsisContext.getMessageBroker();
+ final UpdateNotifier updateNotifier = IsisContext.getUpdateNotifier();
+ final SqlExecutionContext context =
+ new SqlExecutionContext(connector, transactionManager, messageBroker, updateNotifier);
+ try {
+ for (final PersistenceCommand command : commands) {
+ command.execute(context);
+ }
+ connector.commit();
+ } catch (final IsisException e) {
+ LOG.warn("Failure during execution", e);
+ connector.rollback();
+ throw e;
+ } finally {
+ connectionPool.release(connector);
+ }
+ }
+
+ public boolean flush(final PersistenceCommand[] commands) {
+ return false;
+ }
+
+ @Override
+ public List<ObjectAdapter> loadInstancesAndAdapt(final PersistenceQuery query) {
+ if (query instanceof PersistenceQueryFindByTitle) {
+ return findByTitle((PersistenceQueryFindByTitle) query);
+ } else if (query instanceof PersistenceQueryFindAllInstances) {
+ return getAllInstances((PersistenceQueryFindAllInstances) query);
+ } else if (query instanceof PersistenceQueryFindByPattern) {
+ return findByPattern((PersistenceQueryFindByPattern) query);
+ } else {
+ throw new SqlObjectStoreException("Query type not supported: " + query);
+ }
+ }
+
+ private List<ObjectAdapter> findByPattern(final PersistenceQueryFindByPattern query) {
+ final ObjectSpecification specification = query.getSpecification();// query.getPattern().getSpecification();//
+ // getSpecification();
+ final DatabaseConnector connector = connectionPool.acquire();
+ try {
+ final List<ObjectAdapter> matchingInstances = Lists.newArrayList();
+
+ addSpecQueryInstances(specification, connector, query, matchingInstances);
+ return matchingInstances;
+
+ } finally {
+ connectionPool.release(connector);
+ }
+ }
+
+ private void addSpecQueryInstances(final ObjectSpecification specification, final DatabaseConnector connector,
+ final PersistenceQueryFindByPattern query, final List<ObjectAdapter> matchingInstances) {
+
+ if (specification.isAbstract() == false) {
+ final ObjectMapping mapper = objectMappingLookup.getMapping(specification, connector);
+ final Vector<ObjectAdapter> instances = mapper.getInstances(connector, specification, query);
+ matchingInstances.addAll(instances);
+
+ }
+ if (specification.hasSubclasses()) {
+ final List<ObjectSpecification> subclasses = specification.subclasses();
+ for (final ObjectSpecification subclassSpec : subclasses) {
+ addSpecQueryInstances(subclassSpec, connector, query, matchingInstances);
+ }
+ }
+ }
+
+ private List<ObjectAdapter> getAllInstances(final PersistenceQueryFindAllInstances criteria) {
+ final ObjectSpecification spec = criteria.getSpecification();
+ return allInstances(spec);
+ }
+
+ private List<ObjectAdapter> allInstances(final ObjectSpecification spec) {
+ final DatabaseConnector connector = connectionPool.acquire();
+ final List<ObjectAdapter> matchingInstances = Lists.newArrayList();
+
+ addSpecInstances(spec, connector, matchingInstances);
+
+ connectionPool.release(connector);
+ return matchingInstances;
+ }
+
+ private void addSpecInstances(final ObjectSpecification spec, final DatabaseConnector connector,
+ final List<ObjectAdapter> matchingInstances) {
+
+ if (!spec.isAbstract()) {
+ final ObjectMapping mapper = objectMappingLookup.getMapping(spec, connector);
+ final List<ObjectAdapter> instances = mapper.getInstances(connector, spec);
+ matchingInstances.addAll(instances);
+ }
+
+ if (spec.hasSubclasses()) {
+ final List<ObjectSpecification> subclasses = spec.subclasses();
+ for (final ObjectSpecification subclassSpec : subclasses) {
+ addSpecInstances(subclassSpec, connector, matchingInstances);
+ }
+ }
+
+ }
+
+ private List<ObjectAdapter> findByTitle(final PersistenceQueryFindByTitle criteria) {
+ final ObjectSpecification spec = criteria.getSpecification();
+ final DatabaseConnector connector = connectionPool.acquire();
+ final ObjectMapping mapper = objectMappingLookup.getMapping(spec, connector);
+
+ final Vector<ObjectAdapter> instances = mapper.getInstances(connector, spec, criteria.getTitle());
+ connectionPool.release(connector);
+
+ return instances;
+ }
+
+
+ @Override
+ public ObjectAdapter loadInstanceAndAdapt(final TypedOid oid) {
+ final DatabaseConnector connection = connectionPool.acquire();
+ final ObjectSpecification objectSpec = getSpecificationLookup().lookupBySpecId(oid.getObjectSpecId());
+ final ObjectMapping mapper = objectMappingLookup.getMapping(objectSpec, connection);
+ final ObjectAdapter object = mapper.getObject(connection, oid);
+ connectionPool.release(connection);
+ return object;
+ }
+
+ @Override
+ public RootOid getOidForService(ObjectSpecification serviceSpec) {
+
+ final DatabaseConnector connector = connectionPool.acquire();
+ try {
+ final StringBuffer sql = new StringBuffer();
+ sql.append("select ");
+ sql.append(Defaults.getPkIdLabel());
+ sql.append(" from ");
+ sql.append(Sql.tableIdentifier(TABLE_NAME));
+ sql.append(" where ");
+ sql.append(Defaults.getIdColumn());
+ sql.append(" = ?");
+ connector.addToQueryValues(serviceSpec.getSpecId().asString());
+
+ final Results results = connector.select(sql.toString());
+ if (!results.next()) {
+ return null;
+ }
+ final int id = results.getInt(Defaults.getPkIdLabel());
+ return RootOidDefault.create(serviceSpec.getSpecId(), ""+id);
+
+ } finally {
+ connectionPool.release(connector);
+ }
+ }
+
+ @Override
+ public boolean hasInstances(final ObjectSpecification spec) {
+ final DatabaseConnector connection = connectionPool.acquire();
+ final ObjectMapping mapper = objectMappingLookup.getMapping(spec, connection);
+ final boolean hasInstances = mapper.hasInstances(connection, spec);
+ connectionPool.release(connection);
+ return hasInstances;
+ }
+
+ @Override
+ public void resolveField(final ObjectAdapter object, final ObjectAssociation field) {
+ if (field.isOneToManyAssociation()) {
+ final DatabaseConnector connection = connectionPool.acquire();
+ final ObjectSpecification spec = object.getSpecification();
+ final ObjectMapping mapper = objectMappingLookup.getMapping(spec, connection);
+ mapper.resolveCollection(connection, object, field);
+ connectionPool.release(connection);
+ } else {
+ resolveImmediately(field.get(object));
+ }
+ }
+
+ @Override
+ public void resolveImmediately(final ObjectAdapter object) {
+ final DatabaseConnector connector = connectionPool.acquire();
+ final ObjectMapping mapping = objectMappingLookup.getMapping(object, connector);
+ mapping.resolve(connector, object);
+ connectionPool.release(connector);
+ }
+
+ ///////////////////////////////////////////////////////////
+ // Dependencies (injected)
+ ///////////////////////////////////////////////////////////
+
+ public void setConnectionPool(final DatabaseConnectorPool connectionPool) {
+ this.connectionPool = connectionPool;
+ }
+
+ public void setMapperLookup(final ObjectMappingLookup mapperLookup) {
+ this.objectMappingLookup = mapperLookup;
+ }
+
+
+ ///////////////////////////////////////////////////////////
+ // Dependencies (from context)
+ ///////////////////////////////////////////////////////////
+
+ protected AdapterManager getAdapterManager() {
+ return IsisContext.getPersistenceSession().getAdapterManager();
+ }
+
+ protected SpecificationLoader getSpecificationLookup() {
+ return IsisContext.getSpecificationLoader();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/0861ed93/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/SqlObjectStoreException.java
----------------------------------------------------------------------
diff --git a/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/SqlObjectStoreException.java b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/SqlObjectStoreException.java
new file mode 100644
index 0000000..03c8fab
--- /dev/null
+++ b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/SqlObjectStoreException.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.objectstores.sql;
+
+import org.apache.isis.runtimes.dflt.runtime.persistence.ObjectPersistenceException;
+
+public class SqlObjectStoreException extends ObjectPersistenceException {
+ private static final long serialVersionUID = 1L;
+
+ public SqlObjectStoreException() {
+ super();
+ }
+
+ public SqlObjectStoreException(final String s) {
+ super(s);
+ }
+
+ public SqlObjectStoreException(final String s, final Throwable cause) {
+ super(s, cause);
+ }
+
+ public SqlObjectStoreException(final Throwable cause) {
+ super(cause);
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/0861ed93/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/SqlPersistorInstaller.java
----------------------------------------------------------------------
diff --git a/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/SqlPersistorInstaller.java b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/SqlPersistorInstaller.java
new file mode 100644
index 0000000..6a544a8
--- /dev/null
+++ b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/SqlPersistorInstaller.java
@@ -0,0 +1,88 @@
+/*
+ * 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.objectstores.sql;
+
+import org.apache.isis.core.commons.config.IsisConfiguration;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapterFactory;
+import org.apache.isis.runtimes.dflt.objectstores.sql.auto.AutoMapperFactory;
+import org.apache.isis.runtimes.dflt.objectstores.sql.jdbc.JdbcConnectorFactory;
+import org.apache.isis.runtimes.dflt.objectstores.sql.jdbc.installer.JdbcFieldMappingFactoryInstaller;
+import org.apache.isis.runtimes.dflt.runtime.installerregistry.installerapi.PersistenceMechanismInstallerAbstract;
+import org.apache.isis.runtimes.dflt.runtime.persistence.objectstore.ObjectStoreSpi;
+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.IdentifierGenerator;
+
+public class SqlPersistorInstaller extends PersistenceMechanismInstallerAbstract {
+
+ public static final String NAME = "sql";
+
+ private SqlObjectStore objectStore;
+ private DatabaseConnectorPool connectionPool;
+
+ public SqlPersistorInstaller() {
+ super(NAME);
+ }
+
+ @Override
+ protected ObjectStoreSpi createObjectStore(final IsisConfiguration configuration, final ObjectAdapterFactory objectFactory, final AdapterManagerSpi adapterManager) {
+
+ if (objectStore == null) {
+ final FieldMappingLookup fieldMappingLookup = new FieldMappingLookup();
+ final JdbcFieldMappingFactoryInstaller installer = new JdbcFieldMappingFactoryInstaller();
+
+ Defaults.initialise(SqlObjectStore.BASE_NAME, IsisContext.getConfiguration());
+
+ installer.load(fieldMappingLookup);
+ // fieldMappingLookup.setValueMappingFactory(new
+ // JdbcFieldMappingFactoryInstaller());
+
+ final ObjectMappingLookup objectMappingLookup = new ObjectMappingLookup();
+ objectMappingLookup.setValueMappingLookup(fieldMappingLookup);
+ objectMappingLookup.setObjectMappingFactory(new AutoMapperFactory());
+ objectMappingLookup.setConnectionPool(connectionPool);
+
+ final SqlObjectStore objectStore = new SqlObjectStore();
+ objectStore.setMapperLookup(objectMappingLookup);
+ objectStore.setConnectionPool(connectionPool);
+ this.objectStore = objectStore;
+ }
+ return objectStore;
+ }
+
+ public SqlObjectStore getObjectStore() {
+ return objectStore;
+ }
+
+ @Override
+ public IdentifierGenerator createIdentifierGenerator(final IsisConfiguration configuration) {
+ final DatabaseConnectorFactory connectorFactory = new JdbcConnectorFactory();
+ connectionPool = new DatabaseConnectorPool(connectorFactory, 1);
+
+ return new SqlIdentifierGenerator(connectionPool);
+ }
+
+ /*
+ *
+ *
+ * @Override protected AdapterManagerExtended createAdapterManager(final
+ * IsisConfiguration configuration) { return new XmlAdapterManager(); }
+ */
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/0861ed93/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/StoredProcedure.java
----------------------------------------------------------------------
diff --git a/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/StoredProcedure.java b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/StoredProcedure.java
new file mode 100644
index 0000000..c18c3f3
--- /dev/null
+++ b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/StoredProcedure.java
@@ -0,0 +1,26 @@
+/*
+ * 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.objectstores.sql;
+
+public interface StoredProcedure {
+
+ boolean getBoolean(int i);
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/0861ed93/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/TitleMapping.java
----------------------------------------------------------------------
diff --git a/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/TitleMapping.java b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/TitleMapping.java
new file mode 100644
index 0000000..1ff9a7f
--- /dev/null
+++ b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/TitleMapping.java
@@ -0,0 +1,71 @@
+/*
+ * 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.objectstores.sql;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+
+public class TitleMapping {
+ private final String column = Sql.identifier("NO_title");
+
+ protected String getColumn() {
+ return column;
+ }
+
+ public void appendWhereClause(final StringBuffer sql, final String title) {
+ appendAssignment(sql, title);
+ }
+
+ private void appendAssignment(final StringBuffer sql, final String title) {
+ sql.append(column);
+ sql.append(" = ");
+ appendTitle(sql, title);
+ }
+
+ public void appendColumnDefinitions(final StringBuffer sql) {
+ sql.append(column);
+ sql.append(" ");
+ sql.append("varchar(200)");
+ }
+
+ public void appendColumnNames(final StringBuffer sql) {
+ sql.append(column);
+ }
+
+ public void appendInsertValues(final DatabaseConnector connector, final StringBuffer sql, final ObjectAdapter object) {
+ if (object == null) {
+ sql.append("NULL");
+ } else {
+ connector.addToQueryValues(object.titleString().toLowerCase());
+ }
+ sql.append("?");
+ }
+
+ private void appendTitle(final StringBuffer sql, final String title) {
+ final String titleString = title.toLowerCase();
+ sql.append(Sql.escapeAndQuoteValue(titleString));
+ }
+
+ public void appendUpdateAssignment(final DatabaseConnector connector, final StringBuffer sql, final ObjectAdapter object) {
+ sql.append(column);
+ sql.append(" = ");
+ appendInsertValues(connector, sql, object);
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/0861ed93/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/VersionMapping.java
----------------------------------------------------------------------
diff --git a/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/VersionMapping.java b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/VersionMapping.java
new file mode 100644
index 0000000..b6d4ca2
--- /dev/null
+++ b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/VersionMapping.java
@@ -0,0 +1,106 @@
+/*
+ * 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.objectstores.sql;
+
+import java.sql.Timestamp;
+import java.util.Date;
+
+import org.apache.isis.core.metamodel.adapter.version.SerialNumberVersion;
+import org.apache.isis.core.metamodel.adapter.version.Version;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+
+public class VersionMapping {
+ private String lastActivityDateColumn;
+ private String lastActivityUserColumn;
+ private String versionColumn;
+
+ public void init() {
+ lastActivityDateColumn = Sql.identifier("MODIFIED_ON");
+ lastActivityUserColumn = Sql.identifier("MODIFIED_BY");
+ versionColumn = Sql.identifier("VERSION");
+ }
+
+ public String insertColumns() {
+ return versionColumn + ", " + lastActivityUserColumn + ", " + lastActivityDateColumn;
+ }
+
+ public String insertValues(final DatabaseConnector connector, final Version version) {
+ connector.addToQueryValues(version.getSequence());
+ IsisContext.getSession().getAuthenticationSession().getUserName();
+ String user = IsisContext.getSession().getAuthenticationSession().getUserName();// version.getUser();
+ if (user == "") {
+ user = "unknown";
+ }
+ connector.addToQueryValues(user);
+ connector.addToQueryValues(new Timestamp(new Date().getTime()));
+ return "?,?,?";
+ }
+
+ public String whereClause(final DatabaseConnector connector, final Version version) {
+ connector.addToQueryValues(version.getSequence());
+ return versionColumn + " = ?";
+ }
+
+ public String updateAssigment(final DatabaseConnector connector, final long nextSequence) {
+ connector.addToQueryValues(nextSequence);
+ return versionColumn + " = ?";
+ }
+
+ public String appendColumnNames() {
+ final StringBuffer sql = new StringBuffer();
+ sql.append(versionColumn);
+ sql.append(",");
+ sql.append(lastActivityUserColumn);
+ sql.append(",");
+ sql.append(lastActivityDateColumn);
+ return sql.toString();
+ }
+
+ public String appendColumnDefinitions() {
+ final StringBuffer sql = new StringBuffer();
+
+ sql.append(versionColumn);
+ sql.append(" bigint");
+
+ sql.append(",");
+ sql.append(lastActivityUserColumn);
+ sql.append(" varchar(32)");
+
+ sql.append(",");
+ sql.append(lastActivityDateColumn);
+ sql.append(" " + Defaults.TYPE_TIMESTAMP());
+
+ return sql.toString();
+ }
+
+ public Object appendUpdateValues(final DatabaseConnector connector, final long versionSequence) {
+ connector.addToQueryValues(versionSequence);
+ return versionColumn + "= ?";
+ }
+
+ public Version getLock(final Results rs) {
+ final long number = rs.getLong(versionColumn);
+ final String user = rs.getString(lastActivityUserColumn);
+ final Date time = rs.getJavaDateTime(lastActivityDateColumn, Defaults.getCalendar());
+ final Version version = SerialNumberVersion.create(number, user, time);
+ return version;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/0861ed93/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AbstractAutoMapper.java
----------------------------------------------------------------------
diff --git a/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AbstractAutoMapper.java b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AbstractAutoMapper.java
new file mode 100644
index 0000000..567626f
--- /dev/null
+++ b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AbstractAutoMapper.java
@@ -0,0 +1,365 @@
+/*
+ * 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.objectstores.sql.auto;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.collect.Maps;
+
+import org.apache.log4j.Logger;
+
+import org.apache.isis.core.commons.config.IsisConfiguration;
+import org.apache.isis.core.commons.exceptions.NotYetImplementedException;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+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.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.OneToOneAssociation;
+import org.apache.isis.runtimes.dflt.objectstores.sql.AbstractMapper;
+import org.apache.isis.runtimes.dflt.objectstores.sql.CollectionMapper;
+import org.apache.isis.runtimes.dflt.objectstores.sql.DatabaseConnector;
+import org.apache.isis.runtimes.dflt.objectstores.sql.Defaults;
+import org.apache.isis.runtimes.dflt.objectstores.sql.FieldMappingLookup;
+import org.apache.isis.runtimes.dflt.objectstores.sql.ObjectMappingLookup;
+import org.apache.isis.runtimes.dflt.objectstores.sql.Sql;
+import org.apache.isis.runtimes.dflt.objectstores.sql.SqlObjectStoreException;
+import org.apache.isis.runtimes.dflt.objectstores.sql.mapping.FieldMapping;
+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.PersistenceSession;
+
+public abstract class AbstractAutoMapper extends AbstractMapper {
+
+ private static final Logger LOG = Logger.getLogger(AbstractAutoMapper.class);
+
+ protected final Map<ObjectAssociation, FieldMapping> fieldMappingByField = Maps.newLinkedHashMap();
+
+ protected CollectionMapper collectionMappers[];
+ protected String collectionMapperFields[];
+ protected boolean dbCreatesId;
+
+ protected ObjectSpecification specification;
+ protected String table;
+
+ final String className;
+ final String parameterBase;
+ final FieldMappingLookup lookup;
+ final ObjectMappingLookup objectMappingLookup;
+
+ protected AbstractAutoMapper(final String className, final String parameterBase, final FieldMappingLookup lookup, final ObjectMappingLookup objectMappingLookup) {
+ this.specification = specificationFor(className);
+ this.className = className;
+ this.parameterBase = parameterBase;
+ this.lookup = lookup;
+ this.objectMappingLookup = objectMappingLookup;
+ }
+
+ protected AbstractAutoMapper(final FieldMappingLookup lookup, final AbstractAutoMapper abstractAutoMapper, final String className) {
+
+ this.specification = getSpecificationLoader().loadSpecification(className);
+ this.className = className;
+
+ this.parameterBase = null;
+ this.lookup = null;
+ this.objectMappingLookup = null;
+ }
+
+ private static ObjectSpecification specificationFor(final String className) {
+ ObjectSpecification specification = IsisContext.getSpecificationLoader().loadSpecification(className);
+ List<OneToOneAssociation> properties = specification.getProperties();
+ if (isNullOrEmpty(properties) && !specification.isAbstract()) {
+ throw new SqlObjectStoreException(specification.getFullIdentifier() + " has no fields: " + specification);
+ }
+ return specification;
+ }
+
+
+ protected void setUpFieldMappers() {
+ setUpFieldMappers(lookup, objectMappingLookup, className, parameterBase);
+ }
+
+ private void setUpFieldMappers(final FieldMappingLookup lookup, final ObjectMappingLookup objectMappingLookup, final String className, final String parameterBase) {
+ final IsisConfiguration configParameters = getConfiguration();
+ table = configParameters.getString(parameterBase + ".table." + className);
+ if (table == null) {
+ final String name = getTableNameFromSpecification(specification);
+ table = name;
+ } else {
+ table = Sql.tableIdentifier(table);
+ }
+
+ dbCreatesId = configParameters.getBoolean(parameterBase + "db-ids", false);
+ if (configParameters.getBoolean(parameterBase + "all-fields", true)) {
+ setupFullMapping(lookup, objectMappingLookup, className, configParameters, parameterBase);
+ } else {
+ // setupSpecifiedMapping(specification, configParameters,
+ // parameterBase);
+ }
+
+ LOG.info("table mapping: " + table + " (" + columnList(fieldMappingByField) + ")");
+ }
+
+ protected String getTableNameFromSpecification(final ObjectSpecification objectSpecification) {
+ return Sql.tableIdentifier(Sql.sqlName(Defaults.getTablePrefix() + objectSpecification.getShortIdentifier()));
+ }
+
+ protected List<ObjectAssociation> fields = new ArrayList<ObjectAssociation>();
+
+ protected void getExtraFields(final List<ObjectAssociation> fields) {
+ }
+
+ private void setupFullMapping(final FieldMappingLookup lookup, final ObjectMappingLookup objectMapperLookup, final String className, final IsisConfiguration configParameters, final String parameterBase) {
+
+ fields.addAll(specification.getAssociations());
+
+ int simpleFieldCount = 0;
+ int collectionFieldCount = 0;
+ for (int i = 0; i < fields.size(); i++) {
+ if (fields.get(i).isNotPersisted()) {
+ continue;
+ } else if (fields.get(i).isOneToManyAssociation()) {
+ collectionFieldCount++;
+ } else {
+ simpleFieldCount++;
+ }
+ }
+
+ final ObjectAssociation[] oneToOneProperties = new ObjectAssociation[simpleFieldCount];
+ final ObjectAssociation[] oneToManyProperties = new ObjectAssociation[collectionFieldCount];
+ collectionMappers = new CollectionMapper[collectionFieldCount];
+ collectionMapperFields = new String[collectionFieldCount];
+ final IsisConfiguration subset = getConfiguration().createSubset(parameterBase + ".mapper.");
+
+ for (int i = 0, simpleFieldNo = 0, collectionFieldNo = 0; i < fields.size(); i++) {
+ final ObjectAssociation field = fields.get(i);
+ if (field.isNotPersisted()) {
+ continue;
+ } else if (field.isOneToManyAssociation()) {
+ oneToManyProperties[collectionFieldNo] = field;
+
+ // TODO: Replace "new ForeignKeyCollectionMapper" with a factory
+ // method(?) to allow a different
+ // default CollectionMapper
+
+ // TODO: I think the default order should be changed - and I
+ // think I (KAM) have dropped support for the
+ // original "association-table" implementation. This means the
+ // current checks are misleading.
+ final String type = subset.getString(field.getId());
+ if (type == null || type.equals("association-table")) {
+ // collectionMappers[collectionFieldNo] = new
+ // AutoCollectionMapper(specification,
+ // oneToManyProperties[collectionFieldNo], lookup);
+ // collectionMappers[collectionFieldNo] = new
+ // ForeignKeyCollectionMapper(oneToManyProperties[collectionFieldNo],
+ // parameterBase, lookup,
+ // objectMapperLookup);
+
+ CollectionMapper collectionMapper = null;
+
+ // Trying to detect recursion, here.
+ // Let ForeignKeyInChildCollectionMapper find itself when a
+ // field is a collection of the current
+ // field type.
+ if (this instanceof ForeignKeyInChildCollectionMapper) {
+ final ForeignKeyInChildCollectionMapper mc = (ForeignKeyInChildCollectionMapper) this;
+
+ if (mc.priorField == field) {
+ collectionMapper = mc;
+ }
+ }
+
+ if (collectionMapper == null) {
+ // TODO: Polymorphism - is it sufficient for the
+ // collectionMapper to handle the subclasses?
+ final ObjectSpecification fieldSpecification = field.getSpecification();
+ if (fieldSpecification.hasSubclasses() || fieldSpecification.isAbstract()) {
+ // PolymorphicForeignKeyInChildCollectionBaseMapper
+ // Or PolymorphicForeignKeyInChildCollectionMapper
+ collectionMapper = new PolymorphicForeignKeyInChildCollectionBaseMapper(oneToManyProperties[collectionFieldNo], parameterBase, lookup, objectMapperLookup, this, field);
+ } else {
+ final ForeignKeyInChildCollectionMapper mapper = new ForeignKeyInChildCollectionMapper(oneToManyProperties[collectionFieldNo], parameterBase, lookup, objectMapperLookup, this, field);
+ mapper.setUpFieldMappers();
+ collectionMapper = mapper;
+ }
+ }
+
+ collectionMappers[collectionFieldNo] = collectionMapper;
+ collectionMapperFields[collectionFieldNo] = field.getId();
+
+ } else if (type.equals("fk-table")) {
+ final String property = parameterBase + field.getId() + ".element-type";
+ final String elementType = configParameters.getString(property);
+ if (elementType == null) {
+ throw new SqlObjectStoreException("Expected property " + property);
+ }
+ /*
+ * collectionMappers[collectionFieldNo] = new
+ * ForeignKeyCollectionMapper(elementType,
+ * oneToManyProperties[collectionFieldNo], parameterBase,
+ * lookup, objectMapperLookup);
+ */
+ } else {
+ // TODO use other mappers where necessary
+ throw new NotYetImplementedException("for " + type);
+ }
+
+ collectionFieldNo++;
+ } else if (field.isOneToOneAssociation()) {
+ oneToOneProperties[simpleFieldNo] = field;
+ simpleFieldNo++;
+ } else {
+ oneToOneProperties[simpleFieldNo] = field;
+ simpleFieldNo++;
+ }
+ }
+
+
+ for (final ObjectAssociation field : oneToOneProperties) {
+ if(fieldMappingByField.containsKey(field)) {
+ continue;
+ }
+ final FieldMapping mapping = lookup.createMapping(specification, field);
+ fieldMappingByField.put(field, mapping);
+ }
+ }
+
+ protected String columnList(final Map<ObjectAssociation, FieldMapping> fieldMappingByField) {
+ return columnList(fieldMappingByField.values());
+ }
+
+ /*
+ * private void setupSpecifiedMapping( final ObjectSpecification
+ * specification, final IsisConfiguration configParameters, final String
+ * parameterBase) { IsisConfiguration columnMappings =
+ * IsisContext.getConfiguration().createSubset(parameterBase + "column");
+ * int columnsSize = columnMappings.size(); // columnNames = new
+ * String[columnsSize]; oneToOneProperties = new
+ * ObjectAssociation[columnsSize];
+ *
+ * int i = 0; for (Enumeration names = columnMappings.propertyNames();
+ * names.hasMoreElements(); i++) { String columnName = (String)
+ * names.nextElement(); String fieldName =
+ * columnMappings.getString(columnName); oneToOneProperties[i] =
+ * specification.getAssociation(fieldName); // columnNames[i] = columnName;
+ * }
+ *
+ * IsisConfiguration collectionMappings =
+ * IsisContext.getConfiguration().createSubset( parameterBase +
+ * "collection"); int collectionsSize = collectionMappings.size();
+ * collectionMappers = new AutoCollectionMapper[collectionsSize];
+ * oneToManyProperties = new ObjectAssociation[collectionsSize];
+ *
+ * int j = 0; for (Enumeration names = collectionMappings.propertyNames();
+ * names.hasMoreElements(); j++) { String propertyName = (String)
+ * names.nextElement(); String collectionName =
+ * collectionMappings.getString(propertyName); String type =
+ * collectionMappings.getString(collectionName);
+ *
+ * oneToManyProperties[j] = specification.getAssociation(collectionName); if
+ * (type.equals("auto")) { collectionMappers[j] = new
+ * AutoCollectionMapper(this, specification, oneToManyProperties[j],
+ * getLookup()); } else { // TODO use other mappers where necessary // new
+ * ReversedAutoAssociationMapper(specification, collectionName,
+ * parameterBase);
+ *
+ * throw new NotYetImplementedException(); } } }
+ */
+ protected String columnList(final Collection<FieldMapping> fieldMappings) {
+ final StringBuffer sql = new StringBuffer();
+ for (final FieldMapping mapping : fieldMappings) {
+ if (sql.length() > 0) {
+ sql.append(",");
+ }
+ mapping.appendColumnNames(sql);
+ }
+ return sql.toString();
+ }
+
+ protected ObjectAdapter getAdapter(final ObjectSpecification spec, final Oid oid) {
+ final ObjectAdapter adapter = getAdapterManager().getAdapterFor(oid);
+ if (adapter != null) {
+ return adapter;
+ }
+
+ // REVIEW: where the oid is a TypedOid, the following two lines could be replaced by getPersistenceSession().recreatePersistentAdapter(oid)
+ // is preferable, since then reuses the PojoRecreator impl defined within SqlPersistorInstaller
+ final Object recreatedPojo = spec.createObject();
+ return getPersistenceSession().mapRecreatedPojo(oid, recreatedPojo);
+ }
+
+ protected FieldMapping fieldMappingFor(final ObjectAssociation field) {
+ return fieldMappingByField.get(field);
+ }
+
+ @Override
+ public boolean needsTables(final DatabaseConnector connection) {
+ for (int i = 0; collectionMappers != null && i < collectionMappers.length; i++) {
+ if (collectionMappers[i].needsTables(connection)) {
+ return true;
+ }
+ }
+ return !connection.hasTable(table);
+ }
+
+ protected String values(final DatabaseConnector connector, final ObjectAdapter object) {
+ final StringBuffer sql = new StringBuffer();
+ for (final FieldMapping mapping : fieldMappingByField.values()) {
+ mapping.appendInsertValues(connector, sql, object);
+ sql.append(",");
+ }
+ return sql.toString();
+ }
+
+
+ private static boolean isNullOrEmpty(List<?> list) {
+ return list == null || list.size() == 0;
+ }
+
+
+
+ @Override
+ public String toString() {
+ return "AbstractAutoMapper [table=" + table + ",noColumns=" + fieldMappingByField.size() + ",specification=" + specification.getFullIdentifier() + "]";
+ }
+
+ protected SpecificationLoaderSpi getSpecificationLoader() {
+ return IsisContext.getSpecificationLoader();
+ }
+
+ protected IsisConfiguration getConfiguration() {
+ return IsisContext.getConfiguration();
+ }
+
+ protected PersistenceSession getPersistenceSession() {
+ return IsisContext.getPersistenceSession();
+ }
+
+ protected AdapterManager getAdapterManager() {
+ return getPersistenceSession().getAdapterManager();
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/0861ed93/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AutoCollectionMapper.java
----------------------------------------------------------------------
diff --git a/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AutoCollectionMapper.java b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AutoCollectionMapper.java
new file mode 100644
index 0000000..a8f7df9
--- /dev/null
+++ b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AutoCollectionMapper.java
@@ -0,0 +1,171 @@
+/*
+ * 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.objectstores.sql.auto;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.ResolveState;
+import org.apache.isis.core.metamodel.adapter.oid.Oid;
+import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
+import org.apache.isis.core.metamodel.facets.typeof.TypeOfFacet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.runtimes.dflt.objectstores.sql.AbstractMapper;
+import org.apache.isis.runtimes.dflt.objectstores.sql.CollectionMapper;
+import org.apache.isis.runtimes.dflt.objectstores.sql.DatabaseConnector;
+import org.apache.isis.runtimes.dflt.objectstores.sql.FieldMappingLookup;
+import org.apache.isis.runtimes.dflt.objectstores.sql.IdMapping;
+import org.apache.isis.runtimes.dflt.objectstores.sql.Results;
+import org.apache.isis.runtimes.dflt.objectstores.sql.Sql;
+import org.apache.isis.runtimes.dflt.objectstores.sql.jdbc.JdbcObjectReferenceMapping;
+import org.apache.isis.runtimes.dflt.objectstores.sql.mapping.ObjectReferenceMapping;
+import org.apache.isis.runtimes.dflt.runtime.persistence.PersistorUtil;
+
+public class AutoCollectionMapper extends AbstractMapper implements CollectionMapper {
+ private static final Logger LOG = Logger.getLogger(AutoCollectionMapper.class);
+ private String tableName;
+ private final ObjectAssociation field;
+ private final ObjectReferenceMapping elementMapping;
+ private final IdMapping idMapping;
+
+ public AutoCollectionMapper(final ObjectSpecification specification, final ObjectAssociation field, final FieldMappingLookup lookup) {
+ this.field = field;
+
+ final ObjectSpecification spec = field.getFacet(TypeOfFacet.class).valueSpec();
+ idMapping = lookup.createIdMapping();
+ elementMapping = lookup.createMapping(spec);
+
+ final String className = specification.getShortIdentifier();
+ final String columnName = field.getId();
+ tableName = Sql.sqlName(className) + "_" + asSqlName(columnName);
+ tableName = Sql.identifier(tableName);
+ }
+
+ @Override
+ public void createTables(final DatabaseConnector connector) {
+ if (!connector.hasTable(tableName)) {
+ final StringBuffer sql = new StringBuffer();
+ sql.append("create table ");
+ sql.append(tableName);
+ sql.append(" (");
+
+ idMapping.appendColumnDefinitions(sql);
+ sql.append(", ");
+ elementMapping.appendColumnDefinitions(sql);
+
+ sql.append(")");
+
+ connector.update(sql.toString());
+ }
+ }
+
+ @Override
+ public void loadInternalCollection(final DatabaseConnector connector, final ObjectAdapter parentAdapter) {
+ final ObjectAdapter collectionAdapter = field.get(parentAdapter);
+ if (!collectionAdapter.canTransitionToResolving()) {
+ return;
+ }
+
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("loading internal collection " + field);
+ }
+
+ try {
+ PersistorUtil.startResolving(collectionAdapter);
+
+ final StringBuffer sql = new StringBuffer();
+ sql.append("select ");
+ idMapping.appendColumnNames(sql);
+ sql.append(", ");
+ elementMapping.appendColumnNames(sql);
+ sql.append(" from ");
+ sql.append(tableName);
+
+ final Results rs = connector.select(sql.toString());
+ final List<ObjectAdapter> list = new ArrayList<ObjectAdapter>();
+ while (rs.next()) {
+ final ObjectAdapter element = ((JdbcObjectReferenceMapping) elementMapping).initializeField(rs);
+ if(LOG.isDebugEnabled()) {
+ LOG.debug(" element " + element.getOid());
+ }
+ list.add(element);
+ }
+ final CollectionFacet collectionFacet = collectionAdapter.getSpecification().getFacet(CollectionFacet.class);
+ collectionFacet.init(collectionAdapter, list.toArray(new ObjectAdapter[list.size()]));
+ rs.close();
+ } finally {
+ PersistorUtil.toEndState(collectionAdapter);
+ }
+ }
+
+ @Override
+ public boolean needsTables(final DatabaseConnector connector) {
+ return !connector.hasTable(tableName);
+ }
+
+ @Override
+ public void saveInternalCollection(final DatabaseConnector connector, final ObjectAdapter parent) {
+ final ObjectAdapter collection = field.get(parent);
+ LOG.debug("saving internal collection " + collection);
+
+ StringBuffer sql = new StringBuffer();
+ sql.append("delete from ");
+ sql.append(tableName);
+ sql.append(" where ");
+ final RootOid oid = (RootOid) parent.getOid();
+ idMapping.appendWhereClause(connector, sql, oid);
+ connector.update(sql.toString());
+
+ sql = new StringBuffer();
+ sql.append("insert into ");
+ sql.append(tableName);
+ sql.append(" (");
+ idMapping.appendColumnNames(sql);
+ sql.append(", ");
+ elementMapping.appendColumnNames(sql);
+ sql.append(" ) values (");
+ idMapping.appendInsertValues(connector, sql, parent);
+ sql.append(", ");
+
+ final CollectionFacet collectionFacet = collection.getSpecification().getFacet(CollectionFacet.class);
+ for (final ObjectAdapter element : collectionFacet.iterable(collection)) {
+ final StringBuffer values = new StringBuffer();
+ elementMapping.appendInsertValues(connector, values, element);
+ connector.update(sql.toString() + values + ")");
+ }
+ }
+
+ @Override
+ public void debugData(final DebugBuilder debug) {
+ debug.appendln(field.getName(), "collection");
+ debug.indent();
+ debug.appendln("Table", tableName);
+ debug.appendln("ID mapping", idMapping);
+ debug.appendln("Element mapping", elementMapping);
+ debug.unindent();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/0861ed93/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AutoMapper.java
----------------------------------------------------------------------
diff --git a/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AutoMapper.java b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AutoMapper.java
new file mode 100644
index 0000000..9c8dda6
--- /dev/null
+++ b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AutoMapper.java
@@ -0,0 +1,510 @@
+/*
+ * 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.objectstores.sql.auto;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Vector;
+
+import org.apache.log4j.Logger;
+
+import org.apache.isis.applib.Identifier;
+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.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.util.InvokeUtils;
+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.notpersisted.NotPersistedFacet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.ObjectSpecificationException;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.runtimes.dflt.objectstores.sql.CollectionMapper;
+import org.apache.isis.runtimes.dflt.objectstores.sql.DatabaseConnector;
+import org.apache.isis.runtimes.dflt.objectstores.sql.Defaults;
+import org.apache.isis.runtimes.dflt.objectstores.sql.FieldMappingLookup;
+import org.apache.isis.runtimes.dflt.objectstores.sql.IdMapping;
+import org.apache.isis.runtimes.dflt.objectstores.sql.ObjectMapping;
+import org.apache.isis.runtimes.dflt.objectstores.sql.ObjectMappingLookup;
+import org.apache.isis.runtimes.dflt.objectstores.sql.Results;
+import org.apache.isis.runtimes.dflt.objectstores.sql.Sql;
+import org.apache.isis.runtimes.dflt.objectstores.sql.SqlObjectStoreException;
+import org.apache.isis.runtimes.dflt.objectstores.sql.TitleMapping;
+import org.apache.isis.runtimes.dflt.objectstores.sql.VersionMapping;
+import org.apache.isis.runtimes.dflt.objectstores.sql.mapping.FieldMapping;
+import org.apache.isis.runtimes.dflt.runtime.persistence.ObjectNotFoundException;
+import org.apache.isis.runtimes.dflt.runtime.persistence.PersistorUtil;
+import org.apache.isis.runtimes.dflt.runtime.persistence.query.PersistenceQueryFindByPattern;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+
+public class AutoMapper extends AbstractAutoMapper implements ObjectMapping, DebuggableWithTitle {
+
+ private static final Logger LOG = Logger.getLogger(AutoMapper.class);
+ private final IdMapping idMapping;
+ private final VersionMapping versionMapping;
+ private final TitleMapping titleMapping;
+ private final boolean useVersioning;
+
+ public AutoMapper(final String className, final String parameterBase, final FieldMappingLookup lookup,
+ final ObjectMappingLookup objectMapperLookup) {
+ super(className, parameterBase, lookup, objectMapperLookup);
+ idMapping = lookup.createIdMapping();
+ versionMapping = lookup.createVersionMapping();
+ titleMapping = lookup.createTitleMapping();
+
+ useVersioning = Defaults.useVersioning(specification.getShortIdentifier());
+
+ setUpFieldMappers();
+ }
+
+ protected VersionMapping getVersionMapping() {
+ return versionMapping;
+ }
+
+ protected IdMapping getIdMapping() {
+ return idMapping;
+ }
+
+ @Override
+ public void createTables(final DatabaseConnector connection) {
+ if (!connection.hasTable(table)) {
+ final StringBuffer sql = new StringBuffer();
+ sql.append("create table ");
+ sql.append(table);
+ sql.append(" (");
+ idMapping.appendCreateColumnDefinitions(sql);
+ sql.append(", ");
+ for (final FieldMapping mapping : fieldMappingByField.values()) {
+ mapping.appendColumnDefinitions(sql);
+ sql.append(",");
+ }
+ titleMapping.appendColumnDefinitions(sql);
+ sql.append(", ");
+ sql.append(versionMapping.appendColumnDefinitions());
+ sql.append(")");
+ connection.update(sql.toString());
+ }
+ for (int i = 0; collectionMappers != null && i < collectionMappers.length; i++) {
+ if (collectionMappers[i].needsTables(connection)) {
+ collectionMappers[i].createTables(connection);
+ }
+ }
+ }
+
+ @Override
+ public void createObject(final DatabaseConnector connector, final ObjectAdapter object) {
+ final int versionSequence = 1;
+ final Version version = createVersion(versionSequence);
+
+ final StringBuffer sql = new StringBuffer();
+ sql.append("insert into " + table + " (");
+ idMapping.appendColumnNames(sql);
+ sql.append(", ");
+ final String columnList = columnList(fieldMappingByField);
+ if (columnList.length() > 0) {
+ sql.append(columnList);
+ sql.append(", ");
+ }
+ titleMapping.appendColumnNames(sql);
+ sql.append(", ");
+ sql.append(versionMapping.insertColumns());
+ sql.append(") values (");
+ idMapping.appendInsertValues(connector, sql, object);
+ sql.append(", ");
+ sql.append(values(connector, object));
+ titleMapping.appendInsertValues(connector, sql, object);
+ sql.append(", ");
+ sql.append(versionMapping.insertValues(connector, version));
+ sql.append(") ");
+
+ connector.insert(sql.toString());
+ object.setVersion(version);
+
+ for (final CollectionMapper collectionMapper : collectionMappers) {
+ collectionMapper.saveInternalCollection(connector, object);
+ }
+ }
+
+ @Override
+ public void destroyObject(final DatabaseConnector connector, final ObjectAdapter adapter) {
+ final StringBuffer sql = new StringBuffer();
+ sql.append("delete from " + table + " WHERE ");
+ final RootOid oid = (RootOid) adapter.getOid();
+ idMapping.appendWhereClause(connector, sql, oid);
+ sql.append(" AND ");
+ sql.append(versionMapping.whereClause(connector, adapter.getVersion()));
+ final int updateCount = connector.update(sql.toString());
+ if (updateCount == 0) {
+ LOG.info("concurrency conflict object " + this + "; no deletion performed");
+ throw new ConcurrencyException("", adapter.getOid());
+ }
+ }
+
+ @Override
+ public Vector<ObjectAdapter> getInstances(final DatabaseConnector connector, final ObjectSpecification spec) {
+ final StringBuffer sql = createSelectStatement();
+ final Vector<ObjectAdapter> instances = new Vector<ObjectAdapter>();
+ loadInstancesToVector(connector, spec, completeSelectStatement(sql), instances);
+ return instances;
+ }
+
+ @Override
+ public Vector<ObjectAdapter> getInstances(final DatabaseConnector connector, final ObjectSpecification spec,
+ final PersistenceQueryFindByPattern query) {
+ final Vector<ObjectAdapter> instances = new Vector<ObjectAdapter>();
+
+ final StringBuffer sql = createSelectStatement();
+ int initialLength = 0;
+
+ int foundFields = 0;
+ final ObjectAdapter pattern = query.getPattern();
+
+ // for all fields in the query.getPattern, build a SQL select clause for
+ // this spec.
+ final Object o = pattern.getObject();
+ final ObjectSpecification patternSpec = pattern.getSpecification();
+ final List<ObjectAssociation> patternAssociations = patternSpec.getAssociations();
+ for (final ObjectAssociation patternAssoc : patternAssociations) {
+ final Method method;
+ final Identifier identifier = patternAssoc.getIdentifier();
+ final String memberName = identifier.getMemberName();
+ final String methodName = memberName.substring(0, 1).toUpperCase() + memberName.substring(1);
+
+ try {
+ if (true) {
+ final ObjectAdapter field = patternAssoc.get(pattern);
+ if (field != null) {
+ final String id = patternAssoc.getId();
+ try {
+ final ObjectAssociation oa = spec.getAssociation(id);
+ final NotPersistedFacet fc = oa.getFacet(NotPersistedFacet.class);
+ if (fc != null) {
+ continue;
+ }
+ } catch (final ObjectSpecificationException e) {
+ // this is OK
+ }
+
+ if (foundFields == 0) {
+ sql.append(" WHERE ");
+ initialLength = sql.length();
+ }
+
+ if (sql.length() > initialLength) {
+ sql.append(" AND ");
+ }
+
+ final FieldMapping fieldMapping = fieldMappingFor(patternAssoc);
+ if (fieldMapping != null) {
+ fieldMapping.appendWhereClause(connector, sql, pattern);
+ } else {
+ // Have to use getXXX method if the fieldMapping is
+ // null..
+ final ObjectSpecification specification = patternAssoc.getSpecification();
+
+ method = o.getClass().getMethod("get" + methodName, (Class<?>[]) null);
+ final Object res = InvokeUtils.invoke(method, o);
+
+ if (specification.isValue()) {
+ // If the property (memberName) is a value type,
+ // use the value.
+ final String fieldName = Sql.sqlFieldName(identifier.getMemberName());
+ sql.append(fieldName + "=?");
+ connector.addToQueryValues(res);
+ } else {
+ throw new SqlObjectStoreException("Unhandled combination!");
+ }
+ }
+ foundFields++;
+ }
+ }
+ } catch (final SecurityException e) {
+ LOG.debug(e.getMessage());
+ } catch (final NoSuchMethodException e) {
+ LOG.info("Unable to invode method: get" + methodName + " in getInstances");
+ LOG.debug(e.getMessage());
+ }
+ }
+ // if (foundFields > 0) {
+ loadInstancesToVector(connector, spec, completeSelectStatement(sql), instances);
+ // }
+ return instances;
+ }
+
+ @Override
+ public Vector<ObjectAdapter> getInstances(final DatabaseConnector connector, final ObjectSpecification spec,
+ final String title) {
+ final Vector<ObjectAdapter> instances = new Vector<ObjectAdapter>();
+
+ final StringBuffer sql = createSelectStatement();
+ sql.append(" WHERE ");
+ titleMapping.appendWhereClause(sql, title);
+ loadInstancesToVector(connector, spec, completeSelectStatement(sql), instances);
+ return instances;
+ }
+
+ @Override
+ public ObjectAdapter getObject(final DatabaseConnector connector, final TypedOid typedOid) {
+ final StringBuffer sql = createSelectStatement();
+ sql.append(" WHERE ");
+ idMapping.appendWhereClause(connector, sql, (RootOid) typedOid);
+ final Results rs = connector.select(completeSelectStatement(sql));
+ final ObjectSpecification objectSpec = getSpecificationLoader().lookupBySpecId(typedOid.getObjectSpecId());
+ if (rs.next()) {
+ return loadMappedObject(connector, objectSpec, rs);
+ } else {
+ throw new ObjectNotFoundException("No object with with " + typedOid + " in table " + table);
+ }
+ }
+
+ @Override
+ public boolean hasInstances(final DatabaseConnector connector, final ObjectSpecification cls) {
+ final String statement = "select count(*) from " + table;
+ final int instances = connector.count(statement);
+ return instances > 0;
+ }
+
+ private StringBuffer createSelectStatement() {
+ final StringBuffer sql = new StringBuffer();
+ sql.append("select ");
+ idMapping.appendColumnNames(sql);
+ sql.append(", ");
+ final String columnList = columnList(fieldMappingByField);
+ if (columnList.length() > 0) {
+ sql.append(columnList);
+ sql.append(", ");
+ }
+ sql.append(versionMapping.insertColumns());
+ sql.append(" from " + table);
+ return sql;
+ } /*
+ * if (whereClause != null) { sql.append(" WHERE "); sql.append(whereClause); } else if (whereClause != null) {
+ * sql.append(" WHERE "); idMapping.appendWhereClause(sql, oid); }
+ */
+
+ private String completeSelectStatement(final StringBuffer sql) {
+ sql.append(" order by ");
+ idMapping.appendColumnNames(sql);
+ return sql.toString();
+ }
+
+ protected void loadFields(final ObjectAdapter adapter, final Results rs) {
+ PersistorUtil.startResolving(adapter);
+ try {
+ for (final FieldMapping mapping : fieldMappingByField.values()) {
+ mapping.initializeField(adapter, rs);
+ }
+ /*
+ * for (int i = 0; i < oneToManyProperties.length; i++) { /* Need to set up collection to be a ghost before
+ * we access as below
+ */
+ // CollectionAdapter collection = (CollectionAdapter)
+ /*
+ * oneToManyProperties[i].get(object); }
+ */
+ adapter.setVersion(versionMapping.getLock(rs));
+ } finally {
+ PersistorUtil.toEndState(adapter);
+ }
+ }
+
+ // KAM
+ private void loadCollections(final DatabaseConnector connector, final ObjectAdapter instance) {
+
+ for (final CollectionMapper mapper : collectionMappers) {
+ mapper.loadInternalCollection(connector, instance);
+ }
+ }
+
+ private void loadInstancesToVector(final DatabaseConnector connector, final ObjectSpecification cls,
+ final String selectStatment, final Vector<ObjectAdapter> instances) {
+ LOG.debug("loading instances from SQL " + table);
+
+ try {
+ final Results rs = connector.select(selectStatment);
+ final int maxInstances = Defaults.getMaxInstances();
+ for (int count = 0; rs.next() && count < maxInstances; count++) {
+ final ObjectAdapter instance = loadMappedObject(connector, cls, rs);
+ LOG.debug(" instance " + instance);
+ instances.addElement(instance);
+ }
+ rs.close();
+ } catch (final SqlObjectStoreException e) {
+ // Invalid SELECT means no object found.. don't worry about it,
+ // here.
+ }
+ }
+
+ private ObjectAdapter loadMappedObject(final DatabaseConnector connector, final ObjectSpecification cls,
+ final Results rs) {
+ final Oid oid = idMapping.recreateOid(rs, specification);
+ final ObjectAdapter adapter = getAdapter(cls, oid);
+
+ if (adapter.canTransitionToResolving()) {
+ loadFields(adapter, rs);
+ loadCollections(connector, adapter); // KAM
+ }
+ return adapter;
+ }
+
+ @Override
+ public void resolve(final DatabaseConnector connector, final ObjectAdapter object) {
+ LOG.debug("loading data from SQL " + table + " for " + object);
+ final StringBuffer sql = new StringBuffer();
+ sql.append("select ");
+ sql.append(columnList(fieldMappingByField));
+ sql.append(",");
+ sql.append(versionMapping.appendColumnNames());
+ sql.append(" from " + table + " WHERE ");
+ final RootOid oid = (RootOid) object.getOid();
+ idMapping.appendWhereClause(connector, sql, oid);
+
+ final Results rs = connector.select(sql.toString());
+ if (rs.next()) {
+ loadFields(object, rs);
+ rs.close();
+
+ for (final CollectionMapper collectionMapper : collectionMappers) {
+ collectionMapper.loadInternalCollection(connector, object);
+ }
+ } else {
+ rs.close();
+ throw new SqlObjectStoreException("Unable to load data from " + table + " with id "
+ + object.getOid().enString(getOidMarshaller()));
+ }
+ }
+
+ @Override
+ public void resolveCollection(final DatabaseConnector connector, final ObjectAdapter object,
+ final ObjectAssociation field) {
+ if (collectionMappers.length > 0) {
+ final DatabaseConnector secondConnector = connector.getConnectionPool().acquire();
+ for (final CollectionMapper collectionMapper : collectionMappers) {
+ collectionMapper.loadInternalCollection(secondConnector, object);
+ }
+ connector.getConnectionPool().release(secondConnector);
+ }
+ }
+
+ @Override
+ public void startup(final DatabaseConnector connector, final ObjectMappingLookup objectMapperLookup) {
+ if (needsTables(connector)) {
+ createTables(connector);
+ }
+ }
+
+ @Override
+ public void save(final DatabaseConnector connector, final ObjectAdapter adapter) {
+ final Version version = adapter.getVersion();
+ final long nextSequence;
+ if (useVersioning) {
+ nextSequence = version.getSequence() + 1;
+ } else {
+ nextSequence = version.getSequence();
+ }
+
+ final StringBuffer sql = new StringBuffer();
+ sql.append("UPDATE " + table + " SET ");
+ for (final FieldMapping mapping : fieldMappingByField.values()) {
+ mapping.appendUpdateValues(connector, sql, adapter);
+ sql.append(", ");
+ }
+ sql.append(versionMapping.updateAssigment(connector, nextSequence));
+ sql.append(", ");
+ titleMapping.appendUpdateAssignment(connector, sql, adapter);
+ sql.append(" WHERE ");
+ final RootOid oid = (RootOid) adapter.getOid();
+ idMapping.appendWhereClause(connector, sql, oid);
+ if (useVersioning) {
+ sql.append(" AND ");
+ sql.append(versionMapping.whereClause(connector, adapter.getVersion()));
+ }
+
+ final int updateCount = connector.update(sql.toString());
+ if (updateCount == 0) {
+ LOG.info("concurrency conflict object " + this + "; no update performed");
+ throw new ConcurrencyException("", adapter.getOid());
+ } else {
+ adapter.setVersion(createVersion(nextSequence));
+ }
+
+ // TODO update collections - change only when needed rather than
+ // reinserting from scratch
+ for (final CollectionMapper collectionMapper : collectionMappers) {
+ collectionMapper.saveInternalCollection(connector, adapter);
+ }
+ }
+
+ @Override
+ public boolean saveCollection(final DatabaseConnector connection, final ObjectAdapter parent, final String fieldName) {
+ int i = 0;
+ for (final String collectionFieldName : collectionMapperFields) {
+ if (collectionFieldName.equals(fieldName)) {
+ final CollectionMapper fieldMapper = collectionMappers[i];
+ fieldMapper.saveInternalCollection(connection, parent);
+ return true;
+ }
+ i++;
+ }
+ return false;
+ }
+
+ // //////////////////////////////////////////////////////////////
+ // debugging, toString
+ // //////////////////////////////////////////////////////////////
+
+ @Override
+ public void debugData(final DebugBuilder debug) {
+ debug.appendln("ID mapping", idMapping);
+ debug.appendln("ID mapping", versionMapping);
+ debug.appendln("ID mapping", titleMapping);
+ for (final FieldMapping mapping : fieldMappingByField.values()) {
+ mapping.debugData(debug);
+ }
+ for (final CollectionMapper collectionMapper : collectionMappers) {
+ collectionMapper.debugData(debug);
+ }
+
+ }
+
+ @Override
+ public String debugTitle() {
+ return toString();
+ }
+
+ @Override
+ public String toString() {
+ return "AutoMapper [table=" + table + ",id=" + idMapping + ",noColumns=" + fieldMappingByField.size()
+ + ",specification=" + specification.getFullIdentifier() + "]";
+ }
+
+ // //////////////////////////////////////////////////////////////
+ // dependencies (from context)
+ // //////////////////////////////////////////////////////////////
+
+ protected OidMarshaller getOidMarshaller() {
+ return IsisContext.getOidMarshaller();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/0861ed93/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AutoMapperFactory.java
----------------------------------------------------------------------
diff --git a/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AutoMapperFactory.java b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AutoMapperFactory.java
new file mode 100644
index 0000000..2f506b4
--- /dev/null
+++ b/framework/component/objectstore/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AutoMapperFactory.java
@@ -0,0 +1,32 @@
+/*
+ * 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.objectstores.sql.auto;
+
+import org.apache.isis.runtimes.dflt.objectstores.sql.FieldMappingLookup;
+import org.apache.isis.runtimes.dflt.objectstores.sql.ObjectMapping;
+import org.apache.isis.runtimes.dflt.objectstores.sql.ObjectMappingFactory;
+import org.apache.isis.runtimes.dflt.objectstores.sql.ObjectMappingLookup;
+
+public class AutoMapperFactory implements ObjectMappingFactory {
+ @Override
+ public ObjectMapping createMapper(final String className, final String propertiesBase, final FieldMappingLookup lookup, final ObjectMappingLookup objectMapperLookup) {
+ return new AutoMapper(className, propertiesBase, lookup, objectMapperLookup);
+ }
+}