diff options
Diffstat (limited to 'das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl')
34 files changed, 3346 insertions, 0 deletions
diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ApplyChangesCommandImpl.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ApplyChangesCommandImpl.java new file mode 100644 index 0000000000..b19aab85e8 --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ApplyChangesCommandImpl.java @@ -0,0 +1,79 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.sql.Connection; + +import org.apache.log4j.Logger; +import org.apache.tuscany.das.rdb.config.wrapper.MappingWrapper; + +import commonj.sdo.DataObject; + +/** + * + */ +public class ApplyChangesCommandImpl extends BaseCommandImpl { + + private final Logger logger = Logger.getLogger(ApplyChangesCommandImpl.class); + + private ChangeSummarizer summarizer = new ChangeSummarizer(); + + public ApplyChangesCommandImpl(MappingWrapper config, Connection connection) { + this.configWrapper = config; + if (connection != null) { + setConnection(connection, config.getConfig()); + } + + } + + public void setConnection(ConnectionImpl connection) { + summarizer.setConnection(connection); + } + + public void execute(DataObject root) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Executing ApplyChangesCmd"); + } + + if (summarizer.getConnection() == null) { + throw new RuntimeException("A connection must be provided"); + } + + if (!root.equals(root.getDataGraph().getRootObject())) { + throw new RuntimeException("'root' argument must be the root of the datagraph"); + } + + summarizer.setMapping(configWrapper); + + Changes changes = summarizer.loadChanges(root); + + boolean success = false; + try { + changes.execute(); + success = true; + } finally { + if (success) { + summarizer.getConnection().cleanUp(); + } else { + summarizer.getConnection().errorCleanUp(); + } + } + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/BaseCommandImpl.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/BaseCommandImpl.java new file mode 100644 index 0000000000..d1b990d421 --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/BaseCommandImpl.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.tuscany.das.rdb.impl; + +import java.sql.Connection; + +import org.apache.tuscany.das.rdb.config.Config; +import org.apache.tuscany.das.rdb.config.wrapper.MappingWrapper; + +public abstract class BaseCommandImpl { + + protected MappingWrapper configWrapper = new MappingWrapper(); + + public void setConnection(Connection connection) { + setConnection(new ConnectionImpl(connection)); + } + + public void setConnection(Connection connection, Config config) { + boolean managed = true; + if (config != null && config.getConnectionInfo() != null) { + managed = config.getConnectionInfo().isManagedtx(); + } + setConnection(connection, managed); + } + + public void setConnection(Connection connection, boolean manageTransaction) { + ConnectionImpl c = new ConnectionImpl(connection); + c.setManageTransactions(manageTransaction); + setConnection(c); + } + + public abstract void setConnection(ConnectionImpl c); + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ChangeFactory.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ChangeFactory.java new file mode 100644 index 0000000000..c348eae54e --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ChangeFactory.java @@ -0,0 +1,177 @@ +/* + * 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.tuscany.das.rdb.impl; + +import org.apache.log4j.Logger; +import org.apache.tuscany.das.rdb.config.Create; +import org.apache.tuscany.das.rdb.config.Delete; +import org.apache.tuscany.das.rdb.config.Table; +import org.apache.tuscany.das.rdb.config.Update; +import org.apache.tuscany.das.rdb.config.wrapper.MappingWrapper; +import org.apache.tuscany.das.rdb.config.wrapper.TableWrapper; +import org.apache.tuscany.das.rdb.generator.impl.DeleteGenerator; +import org.apache.tuscany.das.rdb.generator.impl.InsertGenerator; +import org.apache.tuscany.das.rdb.generator.impl.UpdateGenerator; + +import commonj.sdo.DataObject; + +public class ChangeFactory { + private final Logger logger = Logger.getLogger(ChangeFactory.class); + + private InsertCommandImpl createCommand; + + private UpdateCommandImpl updateCommand; + + private DeleteCommandImpl deleteCommand; + + private final MappingWrapper mapping; + + private final ConnectionImpl connection; + + public ChangeFactory(MappingWrapper mapping, ConnectionImpl connection) { + this.mapping = mapping; + this.connection = connection; + } + + public void setCreateCommand(InsertCommandImpl cmd) { + createCommand = cmd; + } + + public void setUpdateCommand(UpdateCommandImpl cmd) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Setting Update Command to " + cmd); + } + + updateCommand = cmd; + } + + public void setDeleteCommand(DeleteCommandImpl cmd) { + deleteCommand = cmd; + } + + ChangeOperation createUpdateOperation(DataObject changedObject, String propagatedID) { + return new UpdateOperation(getUpdateCommand(changedObject), changedObject, propagatedID); + } + + ChangeOperation createUpdateOperation(DataObject changedObject) { + return createUpdateOperation(changedObject, null); + } + + ChangeOperation createDeleteOperation(DataObject changedObject) { + return new DeleteOperation(getDeleteCommand(changedObject), changedObject); + } + + ChangeOperation createInsertOperation(DataObject changedObject, String propagatedID) { + return new CreateOperation(getCreateCommand(changedObject), changedObject, propagatedID); + } + + private InsertCommandImpl getCreateCommand(DataObject changedObject) { + + if (createCommand == null) { + Table table = mapping.getTableByTypeName(changedObject.getType().getName()); + if (table == null) { + if (changedObject.getType().getProperty("ID") != null) { + // If the table is not defined in the config, assume it has a primary key of "ID" + mapping.addPrimaryKey(changedObject.getType().getName() + ".ID"); + table = mapping.getTableByTypeName(changedObject.getType().getName()); + } else { + throw new RuntimeException("Table " + changedObject.getType().getName() + + " was changed in the DataGraph but is not present in the Config"); + } + } + + Create create = table.getCreate(); + + if (create == null) { + createCommand = InsertGenerator.INSTANCE.getInsertCommand(mapping, changedObject, table); + } else { + createCommand = new InsertCommandImpl(create); + } + createCommand.setConnection(connection); + createCommand.configWrapper = mapping; + } + return createCommand; + } + + private DeleteCommandImpl getDeleteCommand(DataObject changedObject) { + + if (deleteCommand == null) { + Table table = mapping.getTableByTypeName(changedObject.getType().getName()); + if (table == null) { + if (changedObject.getType().getProperty("ID") != null) { + // If the table is not defined in the config, assume it has a primary key of "ID" + mapping.addPrimaryKey(changedObject.getType().getName() + ".ID"); + table = mapping.getTableByTypeName(changedObject.getType().getName()); + } else { + throw new RuntimeException("Table " + changedObject.getType().getName() + + " was changed in the DataGraph but is not present in the Config"); + } + } + + Delete delete = table.getDelete(); + + if (delete == null) { + deleteCommand = DeleteGenerator.INSTANCE.getDeleteCommand(mapping, table);//JIRA-952 + } else { + deleteCommand = new DeleteCommandImpl(delete); + } + deleteCommand.setConnection(connection); + deleteCommand.configWrapper = mapping; + } + return deleteCommand; + } + + private UpdateCommandImpl getUpdateCommand(DataObject changedObject) { + + Table table = mapping.getTableByTypeName(changedObject.getType().getName()); + if (table == null) { + if (changedObject.getType().getProperty("ID") != null) { + mapping.addPrimaryKey(changedObject.getType().getName() + ".ID"); + table = mapping.getTableByTypeName(changedObject.getType().getName()); + } else { + throw new RuntimeException("Table " + changedObject.getType().getName() + + " was changed in the DataGraph but is not present in the Config"); + } + } + Update update = table.getUpdate(); + if (update == null) { + updateCommand = UpdateGenerator.INSTANCE.getUpdateCommand(mapping, changedObject, table); + } else { + TableWrapper t = new TableWrapper(table); + if (t.getCollisionColumn() != null) { + updateCommand = new OptimisticWriteCommandImpl(update); + } else { + updateCommand = new UpdateCommandImpl(update); + } + } + updateCommand.setConnection(connection); + updateCommand.configWrapper = mapping; + + if (this.logger.isDebugEnabled()) { + this.logger.debug("Returning updateCommand: " + updateCommand); + } + + return updateCommand; + } + + public MappingWrapper getConfig() { + return this.mapping; + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ChangeOperation.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ChangeOperation.java new file mode 100644 index 0000000000..81562dcbd7 --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ChangeOperation.java @@ -0,0 +1,87 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.util.Iterator; + +import org.apache.log4j.Logger; + +import commonj.sdo.DataObject; + +/** + */ +public abstract class ChangeOperation { + protected DatabaseObject dObject; + + protected String propagatedID; + + private final Logger logger = Logger.getLogger(ChangeOperation.class); + + private final WriteCommandImpl writeCommand; + + private boolean isInsert; + + + public ChangeOperation(DeleteCommandImpl command) { + writeCommand = command; + } + + public ChangeOperation(InsertCommandImpl command, DataObject changedObject) { + writeCommand = command; + dObject = new DatabaseObject(command.getMappingModel(), changedObject); + this.isInsert = true; + } + + public ChangeOperation(UpdateCommandImpl command, DataObject changedObject) { + writeCommand = command; + dObject = new DatabaseObject(command.getMappingModel(), changedObject); + } + + public void execute() { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Executing change operation"); + } + + Iterator i = writeCommand.getParameters().iterator(); + while (i.hasNext()) { + ParameterImpl parm = (ParameterImpl) i.next(); + + if (this.logger.isDebugEnabled()) { + this.logger.debug("setting " + parm.getName() + " to " + dObject.get(parm.getName())); + } + + parm.setValue(dObject.get(parm.getName())); + } + + writeCommand.basicExecute(); + + if (isInsert && (propagatedID != null)) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Propagating key " + propagatedID); + } + int id = writeCommand.getGeneratedKey(); + dObject.setPropagatedID(propagatedID, id); + } + } + + public String getTableName() { + return dObject.getTableName(); + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ChangeSummarizer.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ChangeSummarizer.java new file mode 100644 index 0000000000..52300e6c9b --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ChangeSummarizer.java @@ -0,0 +1,241 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.apache.tuscany.das.rdb.Command; +import org.apache.tuscany.das.rdb.config.Column; +import org.apache.tuscany.das.rdb.config.Relationship; +import org.apache.tuscany.das.rdb.config.Table; +import org.apache.tuscany.das.rdb.config.wrapper.MappingWrapper; +import org.apache.tuscany.das.rdb.config.wrapper.RelationshipWrapper; +import org.apache.tuscany.das.rdb.config.wrapper.TableWrapper; +import org.apache.tuscany.sdo.impl.ChangeSummaryImpl; + +import commonj.sdo.ChangeSummary; +import commonj.sdo.DataObject; +import commonj.sdo.Property; +import commonj.sdo.Type; + +public class ChangeSummarizer { + + private final Logger logger = Logger.getLogger(ChangeSummarizer.class); + + private Changes changes = new Changes(); + + private FactoryRegistry registry; + + private MappingWrapper mapping = new MappingWrapper(); + + private ConnectionImpl connection; + + private Map generatedKeys = new HashMap(); + + public ChangeSummarizer() { + // Empty Constructor + } + + public Changes loadChanges(DataObject root) { + ChangeSummary changeSummary = root.getDataGraph().getChangeSummary(); + if (changeSummary.isLogging()) { + ((ChangeSummaryImpl) changeSummary).summarize(); + } + + List changedObjects = changeSummary.getChangedDataObjects(); + + if (this.logger.isDebugEnabled()) { + this.logger.debug("List of changed objects contains " + changedObjects.size() + " object(s)"); + } + + changes.setInsertOrder(mapping.getInsertOrder()); + changes.setDeleteOrder(mapping.getDeleteOrder()); + + Iterator i = changedObjects.iterator(); + while (i.hasNext()) { + DataObject o = (DataObject) i.next(); + + if (!(o.equals(root))) { + createChange(changeSummary, o); + } + } + + return changes; + } + + public void createChange(ChangeSummary changeSummary, DataObject changedObject) { + + if (changeSummary.isCreated(changedObject)) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Change is a create"); + } + if (!changeSummary.isDeleted(changedObject)) { + ChangeFactory factory = getRegistry().getFactory(changedObject.getType()); + String propagatedID = (String) generatedKeys.get(changedObject.getType().getName()); + changes.addInsert(factory.createInsertOperation(changedObject, propagatedID)); + } + } else if (changeSummary.isDeleted(changedObject)) { + ChangeFactory factory = getRegistry().getFactory(changedObject.getType()); + if (this.logger.isDebugEnabled()) { + this.logger.debug("Change is a delete"); + } + changes.addDelete(factory.createDeleteOperation(changedObject)); + } else { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Change is a modify"); + } + List attrList = changeSummary.getOldValues(changedObject); + if (hasAttributeChange(attrList)) { + ChangeFactory factory = getRegistry().getFactory(changedObject.getType()); + if (this.logger.isDebugEnabled()) { + this.logger.debug("Attribute Change for " + changedObject.getType().getName()); + } + String propagatedID = (String) generatedKeys.get(changedObject.getType().getName()); + changes.addUpdate(factory.createUpdateOperation(changedObject, propagatedID)); + } else { + List values = changeSummary.getOldValues(changedObject); + Iterator i = values.iterator(); + while (i.hasNext()) { + ChangeSummary.Setting setting = (ChangeSummary.Setting) i.next(); + if (!setting.getProperty().getType().isDataType()) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Reference change for " + changedObject.getType().getName()); + } + Property ref = setting.getProperty(); + if (this.logger.isDebugEnabled()) { + this.logger.debug(ref.getName()); + } + if (hasState(ref, changedObject)) { + ChangeFactory factory = getRegistry().getFactory(changedObject.getType()); + changes.addUpdate(factory.createUpdateOperation(changedObject)); + } + } + } + } + } + + } + + private boolean hasState(Property ref, DataObject changedObject) { + if (ref.getOpposite().isMany()) { + return true; + } + + MappingWrapper mw = this.mapping; + if (mw.getConfig() == null) { + mw = registry.getFactory(changedObject.getType()).getConfig(); + } + if (mw.getConfig() == null) { + return false; + } + + Relationship rel = mw.getRelationshipByReference(ref); + + if (!rel.isMany()) { + if (rel.isKeyRestricted()) { + throw new RuntimeException("Can not modify a one to one relationship that is key restricted"); + } + // This is a one-one relationship + Table t = mapping.getTableByTypeName(changedObject.getType().getName()); + TableWrapper tw = new TableWrapper(t); + RelationshipWrapper rw = new RelationshipWrapper(rel); + if ((rel.getForeignKeyTable().equals(t.getTableName())) + && (Collections.disjoint(tw.getPrimaryKeyProperties(), rw.getForeignKeys()))) { + return true; + } + + } + + return false; + } + + private boolean hasAttributeChange(List theChanges) { + Iterator i = theChanges.iterator(); + while (i.hasNext()) { + ChangeSummary.Setting setting = (ChangeSummary.Setting) i.next(); + if (setting.getProperty().getType().isDataType()) { + return true; + } + } + return false; + } + + public void addCreateCommand(Type type, Command cmd) { + ChangeFactory cf = getRegistry().getFactory(type); + cf.setCreateCommand((InsertCommandImpl) cmd); + ((CommandImpl) cmd).setConnection(connection); + } + + public void addUpdateCommand(Type type, Command cmd) { + ChangeFactory cf = getRegistry().getFactory(type); + cf.setUpdateCommand((UpdateCommandImpl) cmd); + ((CommandImpl) cmd).setConnection(connection); + } + + public void addDeleteCommand(Type type, Command cmd) { + ChangeFactory cf = getRegistry().getFactory(type); + cf.setDeleteCommand((DeleteCommandImpl) cmd); + ((CommandImpl) cmd).setConnection(connection); + + } + + private FactoryRegistry getRegistry() { + if (this.registry == null) { + this.registry = new FactoryRegistry(mapping, connection); + } + return this.registry; + } + + public void setConnection(ConnectionImpl connection) { + this.connection = connection; + } + + public void setMapping(MappingWrapper map) { + this.mapping = map; + + if (mapping.getConfig() == null) { + return; + } + + Iterator i = mapping.getConfig().getTable().iterator(); + while (i.hasNext()) { + Table t = (Table) i.next(); + Iterator columns = t.getColumn().iterator(); + while (columns.hasNext()) { + Column c = (Column) columns.next(); + if (c.isPrimaryKey() && c.isGenerated()) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("adding generated key " + t.getTableName() + "." + c.getColumnName()); + } + + generatedKeys.put(t.getTableName(), c.getColumnName()); + } + } + } + } + + public ConnectionImpl getConnection() { + return this.connection; + } +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/Changes.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/Changes.java new file mode 100644 index 0000000000..2cc5f906c9 --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/Changes.java @@ -0,0 +1,82 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.util.Iterator; +import java.util.List; + +/** + * Manages a set of graph-change operations. This simple implementaiton can be + * replaced with a version that provides R/I sorting + * + */ +public class Changes { + + private InsertList inserts = new InsertList(); + + private UpdateList updates = new UpdateList(); + + private DeleteList deletes = new DeleteList(); + + public void addInsert(ChangeOperation c) { + inserts.add(c); + } + + public void addUpdate(ChangeOperation c) { + updates.add(c); + } + + public void addDelete(ChangeOperation c) { + deletes.add(c); + } + + /** + * Execute all my change + */ + public void execute() { + + Iterator i = inserts.getSortedList().iterator(); + while (i.hasNext()) { + ChangeOperation c = (ChangeOperation) i.next(); + c.execute(); + } + + i = updates.getSortedList().iterator(); + while (i.hasNext()) { + ChangeOperation c = (ChangeOperation) i.next(); + c.execute(); + } + + i = deletes.getSortedList().iterator(); + while (i.hasNext()) { + ChangeOperation c = (ChangeOperation) i.next(); + c.execute(); + } + + } + + public void setInsertOrder(List insertOrder) { + inserts.setOrder(insertOrder); + } + + public void setDeleteOrder(List deleteOrder) { + deletes.setOrder(deleteOrder); + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/CollisionParameter.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/CollisionParameter.java new file mode 100644 index 0000000000..a9cd9b1a40 --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/CollisionParameter.java @@ -0,0 +1,31 @@ +/*
+ * 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.tuscany.das.rdb.impl;
+
+public class CollisionParameter extends ParameterImpl {
+
+ private boolean isSet;
+
+ public void setValue(Object value) {
+ if (!isSet) {
+ this.value = value;
+ isSet = true;
+ }
+ }
+}
diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/CommandImpl.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/CommandImpl.java new file mode 100644 index 0000000000..8c5658935f --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/CommandImpl.java @@ -0,0 +1,99 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.List; + +import org.apache.tuscany.das.rdb.Command; + +import commonj.sdo.DataObject; +import commonj.sdo.helper.XSDHelper; + +public abstract class CommandImpl extends BaseCommandImpl implements Command { + + protected Statement statement; + + protected Parameters parameters = new Parameters(); + + + + protected ResultSetShape resultSetShape; + + public CommandImpl(String sqlString) { + statement = new Statement(sqlString); + + try { + URL url = getClass().getResource("/xml/sdoJava.xsd"); + if (url == null) { + throw new RuntimeException("Could not find resource: xml/sdoJava.xsd"); + } + + InputStream inputStream = url.openStream(); + XSDHelper.INSTANCE.define(inputStream, url.toString()); + inputStream.close(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + + } + + public abstract void execute(); + + public abstract DataObject executeQuery(); + + public void setParameter(int index, Object value) { + parameters.setParameter(index, value); + } + + public void addParameter(ParameterImpl param) { + parameters.add(param); + } + + public List getParameters() { + return parameters.parameterList(); + } + + public Object getParameter(int index) { + return parameters.parameterWithIndex(index).getValue(); + } + + public void setConnection(ConnectionImpl connection) { + statement.setConnection(connection); + } + + protected ConnectionImpl getConnection() { + return statement.getConnection(); + } + + /* + * The default impl is to throw an exception. This is overridden by InsertCommandImpl + */ + public int getGeneratedKey() { + + throw new RuntimeException("This method is only valid for insert commands"); + } + + public void close() { + statement.close(); + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ConnectionImpl.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ConnectionImpl.java new file mode 100644 index 0000000000..76baa8ca0d --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ConnectionImpl.java @@ -0,0 +1,125 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.sql.CallableStatement; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import org.apache.log4j.Logger; + +public class ConnectionImpl { + + private final Logger logger = Logger.getLogger(ConnectionImpl.class); + + private Connection connection; + + private boolean managingTransaction = true; + + private final boolean useGetGeneratedKeys; + + public ConnectionImpl(Connection connection) { + this.connection = connection; + + try { + DatabaseMetaData dbmd = connection.getMetaData(); + + if (dbmd.getDatabaseProductName().contains("Oracle")) { + this.useGetGeneratedKeys = false; + } else { + this.useGetGeneratedKeys = true; + } + if (connection.getAutoCommit()) { + throw new RuntimeException("AutoCommit must be off"); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + + } + + public Connection getJDBCConnection() { + return connection; + } + + public void cleanUp() { + try { + if (managingTransaction) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Committing Transaction"); + } + connection.commit(); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public void errorCleanUp() { + try { + if (managingTransaction) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Rolling back Transaction"); + } + connection.rollback(); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public PreparedStatement prepareStatement(String queryString, String[] returnKeys) throws SQLException { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Preparing Statement: " + queryString); + } + + if (useGetGeneratedKeys) { + return connection.prepareStatement(queryString, Statement.RETURN_GENERATED_KEYS); + } else if (returnKeys.length > 0) { + return connection.prepareStatement(queryString, returnKeys); + } + + return connection.prepareStatement(queryString); + } + + public PreparedStatement preparePagedStatement(String queryString) throws SQLException { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Preparing Statement: " + queryString); + } + + return connection.prepareStatement(queryString, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); + } + + public void setManageTransactions(boolean manageTransactions) { + managingTransaction = manageTransactions; + + } + + public CallableStatement prepareCall(String queryString) throws SQLException { + return connection.prepareCall(queryString); + } + + public boolean useGetGeneratedKeys() { + return this.useGetGeneratedKeys; + } +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/CreateOperation.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/CreateOperation.java new file mode 100644 index 0000000000..0163f96686 --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/CreateOperation.java @@ -0,0 +1,30 @@ +/* + * 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.tuscany.das.rdb.impl; + +import commonj.sdo.DataObject; + +public class CreateOperation extends ChangeOperation { + + public CreateOperation(InsertCommandImpl command, DataObject changedObject, String id) { + super(command, changedObject); + this.propagatedID = id; + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/DASFactoryImpl.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/DASFactoryImpl.java new file mode 100644 index 0000000000..ba80b3bcb5 --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/DASFactoryImpl.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.tuscany.das.rdb.impl; + +import java.io.InputStream; +import java.sql.Connection; + +import org.apache.tuscany.das.rdb.DAS; +import org.apache.tuscany.das.rdb.DASFactory; +import org.apache.tuscany.das.rdb.config.Config; + +public class DASFactoryImpl implements DASFactory { + + public DAS createDAS(InputStream configStream) { + return new DASImpl(configStream); + } + + public DAS createDAS(Config config) { + return new DASImpl(config); + } + + public DAS createDAS(InputStream configStream, Connection connection) { + return new DASImpl(configStream, connection); + } + + public DAS createDAS(Config config, Connection connection) { + return new DASImpl(config, connection); + } + + public DAS createDAS(Connection connection) { + return new DASImpl(connection); + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/DASImpl.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/DASImpl.java new file mode 100644 index 0000000000..863bb5754d --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/DASImpl.java @@ -0,0 +1,313 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.io.InputStream; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.sql.DataSource; + +import org.apache.tuscany.das.rdb.Command; +import org.apache.tuscany.das.rdb.DAS; +import org.apache.tuscany.das.rdb.config.Config; +import org.apache.tuscany.das.rdb.config.ConfigFactory; +import org.apache.tuscany.das.rdb.config.ConnectionInfo; +import org.apache.tuscany.das.rdb.config.wrapper.MappingWrapper; +import org.apache.tuscany.das.rdb.exception.DataSourceInitializationException; +import org.apache.tuscany.das.rdb.util.ConfigUtil; + +import commonj.sdo.DataObject; + +/** + * An ConfiguredCommandFactory produces instances of Command and ApplyChangesCommand. This + * factory is initialized with a configuration that defines + * the commands it produces. + * + */ +public class DASImpl implements DAS { + + private MappingWrapper configWrapper; + + private Connection connection; + + private Map commands = new HashMap(); + + public DASImpl(InputStream stream) { + this(ConfigUtil.loadConfig(stream)); + + } + + public DASImpl(Config inConfig) { + Config cfg = inConfig; + if (cfg == null) { + cfg = ConfigFactory.INSTANCE.createConfig(); + } + this.configWrapper = new MappingWrapper(cfg); + + Iterator i = configWrapper.getConfig().getCommand().iterator(); + while (i.hasNext()) { + org.apache.tuscany.das.rdb.config.Command commandConfig = + (org.apache.tuscany.das.rdb.config.Command) i.next(); + String kind = commandConfig.getKind(); + if (kind.equalsIgnoreCase("select")) { + commands.put(commandConfig.getName(), new ReadCommandImpl(commandConfig.getSQL(), configWrapper, commandConfig.getResultDescriptor())); + } else if (kind.equalsIgnoreCase("update")) { + commands.put(commandConfig.getName(), new UpdateCommandImpl(commandConfig.getSQL())); + } else if (kind.equalsIgnoreCase("insert")) { + commands.put(commandConfig.getName(), new InsertCommandImpl(commandConfig.getSQL(), new String[0])); + } else if (kind.equalsIgnoreCase("delete")) { + commands.put(commandConfig.getName(), new DeleteCommandImpl(commandConfig.getSQL())); + } else if (kind.equalsIgnoreCase("procedure")) { + commands.put(commandConfig.getName(), new SPCommandImpl(commandConfig.getSQL(), configWrapper, commandConfig.getParameter())); + } else { + throw new RuntimeException("Invalid kind of command: " + kind); + } + + } + + } + + public DASImpl(Config inConfig, Connection inConnection) { + this(inConfig); + setConnection(inConnection); + } + + public DASImpl(InputStream configStream, Connection inConnection) { + this(ConfigUtil.loadConfig(configStream), inConnection); + } + + public DASImpl(Connection inConnection) { + this(ConfigFactory.INSTANCE.createConfig()); + setConnection(inConnection); + } + + /* + * (non-Javadoc) + * + * @see org.apache.tuscany.das.rdb.CommandGroup#getApplyChangesCommand() + */ + public ApplyChangesCommandImpl getApplyChangesCommand() { + ApplyChangesCommandImpl cmd = new ApplyChangesCommandImpl(configWrapper, connection); + return cmd; + } + + /* + * (non-Javadoc) + * + * @see org.apache.tuscany.das.rdb.CommandGroup#getCommand(java.lang.String) + */ + public Command getCommand(String name) { + if (!commands.containsKey(name)) { + throw new RuntimeException("CommandGroup has no command named: " + name); + } + CommandImpl cmd = (CommandImpl) commands.get(name); + cmd.setConnection(getConnection(), configWrapper.getConfig()); + return cmd; + } + + public void setConnection(Connection connection) { + this.connection = connection; + } + + public Connection getConnection() { + if (connection == null) { + initializeConnection(); + } + return connection; + } + + private void initializeConnection() { + Config config = configWrapper.getConfig(); + if (config == null || config.getConnectionInfo() == null || + (config.getConnectionInfo().getDataSource() == null && config.getConnectionInfo().getConnectionProperties() == null)) { + throw new RuntimeException("No connection has been provided and no data source has been specified"); + } + + if(config.getConnectionInfo().getDataSource() != null && config.getConnectionInfo().getConnectionProperties() != null){ + throw new RuntimeException("Use either dataSource or ConnectionProperties. Can't use both !"); + } + + ConnectionInfo connectionInfo = configWrapper.getConfig().getConnectionInfo(); + if(config.getConnectionInfo().getConnectionProperties() != null){ + initializeDriverManagerConnection(connectionInfo); + }else{ + initializeDatasourceConnection(connectionInfo); + } + + } + + /** + * Initializes a DB connection on a managed environmet (e.g inside Tomcat) + */ + private void initializeDatasourceConnection(ConnectionInfo connectionInfo){ + Connection connection = null; + + InitialContext ctx; + try { + ctx = new InitialContext(); + } catch (NamingException e) { + throw new RuntimeException(e); + } + try { + DataSource ds = (DataSource) ctx.lookup(connectionInfo.getDataSource()); + try { + connection = ds.getConnection(); + if (connection == null) { + throw new RuntimeException("Could not obtain a Connection from DataSource"); + } + connection.setAutoCommit(false); + setConnection(connection); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } catch (NamingException e) { + throw new RuntimeException(e); + } + } + + /** + * Initialize a DB connection on a J2SE environment + * For more info, see http://java.sun.com/j2se/1.3/docs/guide/jdbc/getstart/drivermanager.html + */ + private void initializeDriverManagerConnection(ConnectionInfo connectionInfo) { + + Connection connection = null; + + if (connectionInfo.getConnectionProperties() == null) { + throw new DataSourceInitializationException("No existing context and no connection properties"); + } + + if (connectionInfo.getConnectionProperties().getDriverClass() == null) { + throw new DataSourceInitializationException("No jdbc driver class specified!"); + } + + try { + //initialize driver and register it with DriverManager + Class.forName(connectionInfo.getConnectionProperties().getDriverClass()); + + //prepare to initialize connection + String databaseUrl = connectionInfo.getConnectionProperties().getDatabaseURL(); + String userName = connectionInfo.getConnectionProperties().getUserName(); + String userPassword = connectionInfo.getConnectionProperties().getPassword(); + int loginTimeout = connectionInfo.getConnectionProperties().getLoginTimeout(); + + DriverManager.setLoginTimeout(loginTimeout); + if( (userName == null || userName.length() ==0) && (userPassword == null || userPassword.length()==0) ){ + //no username or password suplied + connection = DriverManager.getConnection(databaseUrl); + }else{ + connection = DriverManager.getConnection(databaseUrl, userName, userPassword); + } + + if(connection == null){ + throw new DataSourceInitializationException("Error initializing connection : null"); + } + + connection.setAutoCommit(false); + setConnection(connection); + + + }catch(ClassNotFoundException cnf){ + throw new DataSourceInitializationException("JDBC Driver '" + connectionInfo.getConnectionProperties().getDriverClass() + "' not found", cnf); + }catch(SQLException sqle){ + throw new DataSourceInitializationException(sqle.getMessage(), sqle); + } + + } + + public void releaseResources() { + + if (managingConnections()) { + closeConnection(); + } + } + + private void closeConnection() { + if (connection != null) { + try { + connection.close(); + connection = null; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + } + + /** + * If the config has connection properties then we are "managing" the connection via DataSource + */ + private boolean managingConnections() { + + if (configWrapper.getConfig().getConnectionInfo().getDataSource() == null) { + return false; + } + + return true; + + } + + public Command createCommand(String sql) { + return baseCreateCommand(sql, this.configWrapper); + } + + public Command createCommand(String sql, Config config) { + return baseCreateCommand(sql, new MappingWrapper(config)); + } + + private Command baseCreateCommand(String inSql, MappingWrapper config) { + CommandImpl returnCmd = null; + String sql = inSql.trim(); // Remove leading white space + char firstChar = Character.toUpperCase(sql.charAt(0)); + switch (firstChar) { + case 'S': + returnCmd = new ReadCommandImpl(sql, config, null); + break; + case 'I': + returnCmd = new InsertCommandImpl(sql, new String[0]); + break; + case 'U': + returnCmd = new UpdateCommandImpl(sql); + break; + case 'D': + returnCmd = new DeleteCommandImpl(sql); + break; + case '{': + returnCmd = new SPCommandImpl(sql, config, Collections.EMPTY_LIST); + break; + default: + throw new RuntimeException("SQL => " + sql + " is not valid"); + } + + returnCmd.setConnection(getConnection(), config.getConfig()); + return returnCmd; + } + + public void applyChanges(DataObject root) { + getApplyChangesCommand().execute(root); + } + +}
\ No newline at end of file diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/DatabaseObject.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/DatabaseObject.java new file mode 100644 index 0000000000..110fd1bd38 --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/DatabaseObject.java @@ -0,0 +1,202 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.apache.tuscany.das.rdb.config.Column; +import org.apache.tuscany.das.rdb.config.Config; +import org.apache.tuscany.das.rdb.config.KeyPair; +import org.apache.tuscany.das.rdb.config.Relationship; +import org.apache.tuscany.das.rdb.config.Table; +import org.apache.tuscany.das.rdb.config.wrapper.MappingWrapper; +import org.apache.tuscany.das.rdb.config.wrapper.TableWrapper; + +import commonj.sdo.DataObject; +import commonj.sdo.Property; + +/** + * DatabaseObject wraps DataObject. If a field is an FK field, it will return the value from the parent. + * + * + */ +public class DatabaseObject { + + private final Logger logger = Logger.getLogger(DatabaseObject.class); + + private final MappingWrapper mappingWrapper; + + private final DataObject dataObject; + + private Property parentReference; + + private Map keyMappings = new HashMap(); + + public DatabaseObject(Config model, DataObject changedObject) { + this.mappingWrapper = new MappingWrapper(model); + this.dataObject = changedObject; + initialize(); + } + + // Initialize Key Mappings + private void initialize() { + if (mappingWrapper.getConfig() != null) { + List relationships = mappingWrapper.getConfig().getRelationship(); + Iterator i = relationships.iterator(); + while (i.hasNext()) { + Relationship r = (Relationship) i.next(); + if (this.logger.isDebugEnabled()) { + this.logger.debug("Initializing relationship: " + r.getName()); + this.logger.debug("r.getForeignKeyTable():"+r.getForeignKeyTable()); + this.logger.debug("getTypeName():"+getTypeName()); + } + + if (r.getForeignKeyTable().equals(getTypeName())) { + List pairs = r.getKeyPair(); + Iterator iter = pairs.iterator(); + while (iter.hasNext()) { + KeyPair pair = (KeyPair) iter.next(); + keyMappings.put(pair.getForeignKeyColumn(), r); + if (this.logger.isDebugEnabled()) { + this.logger.debug("Putting key pair: " + pair.getPrimaryKeyColumn()+","+pair.getForeignKeyColumn()); + } + } + } + } + } + } + + public Object get(String parameter) { + if (isPartOfPrimaryKey(parameter)) { + return dataObject.get(parameter); + } + + Relationship r = (Relationship) keyMappings.get(parameter); + if (r == null) { + return dataObject.get(parameter); + } + + //JIRA-952 + Table tbl = this.mappingWrapper.getTable(r.getPrimaryKeyTable()); + Property parentRef = null; + if(tbl == null){ + //this is case when config file is not present and + //ConfigHelper helper = new ConfigHelper(); is used + parentRef = getParentReference(r.getPrimaryKeyTable()); + } + else{ + //other cases, its better to use typeName as r.getPrimaryKeyTable() + //gives tableName and tableName and typeName can be different + //and SDO looks for typeName and not tableName. + parentRef = getParentReference((new TableWrapper(tbl)).getTypeName()); + } + + DataObject parent = dataObject.getDataObject(parentRef); + + if (parent == null) { + return null; + } + String parentKey = getParentKey(r, parameter); + return parent.get(parentKey); + + } + + private String getParentKey(Relationship r, String parameter) { + List keyPairs = r.getKeyPair(); + Iterator i = keyPairs.iterator(); + while (i.hasNext()) { + KeyPair pair = (KeyPair) i.next(); + if (pair.getForeignKeyColumn().equals(parameter)) { + return pair.getPrimaryKeyColumn(); + } + } + return null; + } + + public Property getParentReference(String parentName) { + if (this.parentReference == null) { + Iterator i = dataObject.getType().getProperties().iterator(); + while (i.hasNext()) { + Property ref = (Property) i.next(); + if ((!ref.getType().isDataType()) && (ref.getType().getName().equals(parentName))) { + this.parentReference = ref; + } + } + } + return this.parentReference; + } + + //JIRA-952 + public String getTableName() { + if (mappingWrapper.getConfig() != null) { + + if(mappingWrapper.getConfig().isDatabaseSchemaNameSupported()){ + if (this.logger.isDebugEnabled()) { + this.logger.debug("DatabaseObject.getTableName:(schemaName.tableName) " + + mappingWrapper.getTableByTypeName(getTypeName()).getSchemaName()+"."+ + mappingWrapper.getTableByTypeName(getTypeName()).getTableName()); + } + + return (mappingWrapper.getTableByTypeName(getTypeName()).getSchemaName()+"."+ + mappingWrapper.getTableByTypeName(getTypeName()).getTableName()); + } + else{ + if (this.logger.isDebugEnabled()) { + this.logger.debug("DatabaseObject.getTableName: " + mappingWrapper.getTableByTypeName(getTypeName()).getTableName()); + } + + return mappingWrapper.getTableByTypeName(getTypeName()).getTableName(); + } + } + return null; + } + + public String getTypeName() { + if (this.logger.isDebugEnabled()) { + this.logger.debug("DatabaseObject.getTypeName: " + dataObject.getType().getName()); + } + return dataObject.getType().getName(); + } + + public void setPropagatedID(String propagatedID, int id) { + dataObject.setInt(propagatedID, id); + } + + private boolean isPartOfPrimaryKey(String parameter) { + if (mappingWrapper.getConfig() == null) { + return false; + } + + Table t = mappingWrapper.getTable(getTableName()); + if (t == null) { + return false; + } + Column c = mappingWrapper.getColumnByPropertyName(t, parameter); + if (c == null) { + return false; + } + + return c.isPrimaryKey(); + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/DeleteCommandImpl.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/DeleteCommandImpl.java new file mode 100644 index 0000000000..78e38cee0b --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/DeleteCommandImpl.java @@ -0,0 +1,34 @@ +/* + * 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.tuscany.das.rdb.impl; + +import org.apache.tuscany.das.rdb.config.Delete; + +public class DeleteCommandImpl extends WriteCommandImpl { + + public DeleteCommandImpl(String sqlString) { + super(sqlString); + } + + public DeleteCommandImpl(Delete delete) { + super(delete.getSql()); + addParameters(delete.getParameters()); + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/DeleteList.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/DeleteList.java new file mode 100644 index 0000000000..feb7e31411 --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/DeleteList.java @@ -0,0 +1,77 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * DeleteList will sort delete operations so that child objects are deleted before their parents + * + * + */ +public class DeleteList { + + private Map opsByTableName = new HashMap(); + + private List order; + + private List deleteOperations = new ArrayList(); + + public DeleteList() { + super(); + } + + public void add(ChangeOperation op) { + if ((order.size() == 0) || (op.getTableName() == null)) { + deleteOperations.add(op); + } else { + String name = op.getTableName(); + List ops = (List) opsByTableName.get(name); + if (ops == null) { + ops = new ArrayList(); + } + ops.add(op); + opsByTableName.put(name, ops); + } + } + + public Collection getSortedList() { + if ((order.size() > 0) && (opsByTableName.keySet().size() > 0)) { + Iterator i = this.order.iterator(); + while (i.hasNext()) { + String name = (String) i.next(); + if (opsByTableName.get(name) != null) { + deleteOperations.addAll((Collection) opsByTableName.get(name)); + } + } + } + + return deleteOperations; + } + + public void setOrder(List deleteOrder) { + this.order = deleteOrder; + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/DeleteOperation.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/DeleteOperation.java new file mode 100644 index 0000000000..52935599c1 --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/DeleteOperation.java @@ -0,0 +1,38 @@ +/* + * 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.tuscany.das.rdb.impl; + +import org.apache.tuscany.das.rdb.util.DataObjectUtil; + +import commonj.sdo.DataObject; + +public class DeleteOperation extends ChangeOperation { + + /** + * @param command + * @param changedObject + * Objects deleted from the graph have lost their "settings" and must be restored + */ + public DeleteOperation(DeleteCommandImpl command, DataObject changedObject) { + super(command); + this.dObject = new DatabaseObject(command.getMappingModel(), DataObjectUtil.getRestoredCopy(changedObject)); + + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/FactoryRegistry.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/FactoryRegistry.java new file mode 100644 index 0000000000..bb148635c8 --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/FactoryRegistry.java @@ -0,0 +1,57 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.apache.tuscany.das.rdb.config.wrapper.MappingWrapper; + +import commonj.sdo.Type; + +public class FactoryRegistry { + + private final Logger logger = Logger.getLogger(FactoryRegistry.class); + + private Map registry = new HashMap(); + + private final MappingWrapper mapping; + + private final ConnectionImpl connection; + + public FactoryRegistry(MappingWrapper mapping, ConnectionImpl connection) { + this.mapping = mapping; + this.connection = connection; + } + + public ChangeFactory getFactory(Type type) { + ChangeFactory factory = (ChangeFactory) registry.get(type); + if (factory == null) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Creating new ChangeFactory for type " + type.getName()); + } + + factory = new ChangeFactory(mapping, connection); + registry.put(type, factory); + } + return factory; + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/InsertCommandImpl.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/InsertCommandImpl.java new file mode 100644 index 0000000000..048ee7fef5 --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/InsertCommandImpl.java @@ -0,0 +1,66 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.sql.SQLException; + +import org.apache.tuscany.das.rdb.config.Create; + +public class InsertCommandImpl extends WriteCommandImpl { + + private String[] keys; + + public InsertCommandImpl(String sqlString, String[] generatedKeys) { + super(sqlString); + keys = generatedKeys; + } + + public InsertCommandImpl(Create create) { + super(create.getSql()); + addParameters(create.getParameters()); + this.keys = new String[0]; + } + + public void execute() { + + boolean success = false; + try { + statement.executeUpdate(parameters, keys); + success = true; + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + if (success) { + statement.getConnection().cleanUp(); + } else { + statement.getConnection().errorCleanUp(); + } + } + + } + + public int getGeneratedKey() { + try { + return statement.getGeneratedKey(); + } catch (SQLException ex) { + throw new RuntimeException(ex); + } + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/InsertList.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/InsertList.java new file mode 100644 index 0000000000..e61ccfe21e --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/InsertList.java @@ -0,0 +1,95 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; + +/** + * InsertList will sort ChangeOperation objects so that parents are inserted before children + * + * + */ +public class InsertList { + private final Logger logger = Logger.getLogger(InsertList.class); + + private Map opsByTableName = new HashMap(); + + private List insertOperations = new ArrayList(); + + private List order; + + public void add(ChangeOperation op) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Adding insert operation "); + } + + // If nothing has been added yet, or this is no ordering, simply + // add the operation to the list + if ((order.size() == 0) || (op.getTableName() == null)) { + insertOperations.add(op); + } else { + String name = op.getTableName(); + List ops = (List) opsByTableName.get(name); + if (ops == null) { + ops = new ArrayList(); + } + + ops.add(op); + opsByTableName.put(name, ops); + } + } + + public Collection getSortedList() { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Getting sorted insert list"); + } + + if ((order.size() > 0) && opsByTableName.keySet().size() > 0) { + Iterator i = this.order.iterator(); + while (i.hasNext()) { + String name = (String) i.next(); + if (this.logger.isDebugEnabled()) { + this.logger.debug("Adding operations for table " + name); + } + + // A null here means a table is in the config but hasn't been changed here + if (opsByTableName.get(name) != null) { + insertOperations.addAll((Collection) opsByTableName.get(name)); + } + } + } + if (this.logger.isDebugEnabled()) { + this.logger.debug("Returning " + insertOperations.size() + " insert operations"); + } + + return insertOperations; + } + + public void setOrder(List insertOrder) { + this.order = insertOrder; + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ManagedParameterImpl.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ManagedParameterImpl.java new file mode 100644 index 0000000000..d91200fd03 --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ManagedParameterImpl.java @@ -0,0 +1,39 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.math.BigDecimal; + +public class ManagedParameterImpl extends ParameterImpl { + + public void setValue(Object oldValue) { + this.value = updateValue(oldValue); + } + + private Object updateValue(Object oldValue) { + if (oldValue instanceof Integer) { + return Integer.valueOf(((Integer) oldValue).intValue() + 1); + } else if (oldValue instanceof BigDecimal) { + return ((BigDecimal) oldValue).add(new BigDecimal(1)); + } else { + throw new RuntimeException("Unsupported type for managed column: " + oldValue.getClass().getName()); + } + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/OptimisticWriteCommandImpl.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/OptimisticWriteCommandImpl.java new file mode 100644 index 0000000000..0a5f6951e9 --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/OptimisticWriteCommandImpl.java @@ -0,0 +1,48 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.sql.SQLException; + +import org.apache.tuscany.das.rdb.config.Update; +import org.apache.tuscany.das.rdb.exception.OptimisticConcurrencyException; + +public class OptimisticWriteCommandImpl extends UpdateCommandImpl { + + public OptimisticWriteCommandImpl(String sqlString) { + super(sqlString); + } + + public OptimisticWriteCommandImpl(Update update) { + super(update); + addParameters(update.getParameters()); + } + + public void basicExecute() { + try { + int rowsAffected = statement.executeUpdate(parameters); + if (rowsAffected == 0) { + throw new OptimisticConcurrencyException("An update collision occurred"); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/PagerImpl.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/PagerImpl.java new file mode 100644 index 0000000000..27b653763b --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/PagerImpl.java @@ -0,0 +1,69 @@ +/* + * 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.tuscany.das.rdb.impl; + +import org.apache.tuscany.das.rdb.Command; +import org.apache.tuscany.das.rdb.Pager; + +import commonj.sdo.DataObject; + +public class PagerImpl implements Pager { + + private final ReadCommandImpl command; + + private final int size; + + private int idx = 1; + + public PagerImpl(Command command, int size) { + this.command = (ReadCommandImpl) command; + this.command.enablePaging(); + this.size = size; + } + + public DataObject next() { + int start = idx; + int end = idx + size; + idx += size; + command.setStartRow(start); + command.setEndRow(end); + return command.executeQuery(); + } + + public DataObject getPage(int page) { + int end = (page * size) + 1; + int start = end - size; + idx = end; + command.setStartRow(start); + command.setEndRow(end); + return command.executeQuery(); + } + + public DataObject previous() { + int start = idx - (2 * size); + if (start < 1) { + start = 1; + } + int end = start + size; + idx = end; + command.setStartRow(start); + command.setEndRow(end); + return command.executeQuery(); + } +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ParameterImpl.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ParameterImpl.java new file mode 100644 index 0000000000..3e23faf069 --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ParameterImpl.java @@ -0,0 +1,120 @@ +/* + * 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.tuscany.das.rdb.impl; + +import org.apache.tuscany.das.rdb.Converter; + +import commonj.sdo.Type; + +public class ParameterImpl { + + /** + * Value for "Direction" that indicates that a parameter is soley for input. + */ + static final int IN = 1; + + /** + * Value for "Direction" that indicates that a parameter is soley for output. + * Out parameters only apply to Stored Procedures + */ + static final int OUT = 2; + + /** + * Value for "Direction" that indicates that a parameter is for both input and output. + * In-out parameters only apply to stored procedures + */ + static final int IN_OUT = 3; + + protected Object value; + + private int index; + + private Type type; + + private String name; + + private int direction = IN; + + private Converter converter; + + + public ParameterImpl() { + super(); + } + + public ParameterImpl(int index) { + this.index = index; + } + + public void setType(Type type) { + this.type = type; + } + + public void setIndex(int index) { + if (index == 0) { + throw new RuntimeException("Index of zero not allowed"); + } + this.index = index; + } + + public void setName(String name) { + this.name = name; + } + + public void setValue(Object value) { + this.value = value; + } + + public void setDirection(int direction) { + this.direction = direction; + } + + public Type getType() { + return this.type; + } + + public int getIndex() { + return this.index; + } + + public String getName() { + return this.name; + } + + public Object getValue() { + if (getConverter() != null) { + return getConverter().getColumnValue(this.value); + } + + return this.value; + } + + public int getDirection() { + return this.direction; + } + + public void setConverter(Converter converter) { + this.converter = converter; + } + + public Converter getConverter() { + return this.converter; + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/Parameters.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/Parameters.java new file mode 100644 index 0000000000..bebfba9ce9 --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/Parameters.java @@ -0,0 +1,113 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.log4j.Logger; + +import commonj.sdo.Type; + +public class Parameters { + private final Logger logger = Logger.getLogger(Parameters.class); + + private List parameters = new ArrayList(); + + private List inParams = new ArrayList(); + + private List outParams = new ArrayList(); + + public Parameters() { + super(); + } + + public ParameterImpl get(int index) { + return (ParameterImpl) parameters.get(index); + } + + public List outParams() { + return outParams; + } + + public List inParams() { + return inParams; + } + + private void addParameter(ParameterImpl param) { + if (param.getDirection() == ParameterImpl.IN) { + inParams.add(param); + } else if ((param.getDirection() == ParameterImpl.OUT) || (param.getDirection() == ParameterImpl.IN_OUT)) { + outParams.add(param); + } + + this.parameters.add(param); + } + + public void add(ParameterImpl param) { + addParameter(param); + } + + public ParameterImpl findOrCreateParameterWithIndex(int index, int direction, Type sdoType) { + Iterator i = parameters.iterator(); + while (i.hasNext()) { + ParameterImpl param = (ParameterImpl) i.next(); + + if (param.getIndex() == index) { + return param; + } + } + if (this.logger.isDebugEnabled()) { + this.logger.debug("Creating new parameter with index " + index); + } + + ParameterImpl newParam = new ParameterImpl(index); + newParam.setDirection(direction); + newParam.setType(sdoType); + addParameter(newParam); + return newParam; + } + + public List parameterList() { + return parameters; + } + + public ParameterImpl findOrCreateParameterWithIndex(int index) { + return findOrCreateParameterWithIndex(index, ParameterImpl.IN, null); + } + + public void setParameter(int index, Object value) { + ParameterImpl param = findOrCreateParameterWithIndex(index); + param.setValue(value); + } + + public ParameterImpl parameterWithIndex(int index) { + Iterator i = parameters.iterator(); + while (i.hasNext()) { + ParameterImpl param = (ParameterImpl) i.next(); + + if (param.getIndex() == index) { + return param; + } + } + return null; + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ReadCommandImpl.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ReadCommandImpl.java new file mode 100644 index 0000000000..defebc6f3e --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ReadCommandImpl.java @@ -0,0 +1,124 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.sql.SQLException; +import java.util.List; + +import org.apache.tuscany.das.rdb.config.wrapper.MappingWrapper; +import org.apache.tuscany.das.rdb.graphbuilder.impl.GraphBuilderMetadata; +import org.apache.tuscany.das.rdb.graphbuilder.impl.ResultSetProcessor; +import org.apache.tuscany.sdo.util.SDOUtil; + +import commonj.sdo.ChangeSummary; +import commonj.sdo.DataGraph; +import commonj.sdo.DataObject; + +public class ReadCommandImpl extends CommandImpl { + + private int startRow = 1; + + private int endRow = Integer.MAX_VALUE; + + public ReadCommandImpl(String sqlString, MappingWrapper mapping, List resultDescriptor) { + super(sqlString); + this.configWrapper = mapping; + + if (resultDescriptor != null && !resultDescriptor.isEmpty()) { + this.resultSetShape = new ResultSetShape(resultDescriptor, configWrapper.getConfig());//JIRA-952 + } + } + + + public void execute() { + throw new UnsupportedOperationException(); + } + + public DataObject executeQuery() { + + if (statement.getConnection() == null) { + throw new RuntimeException("A DASConnection object must be specified before executing the query."); + } + + boolean success = false; + try { + List results = statement.executeQuery(parameters); + success = true; + return buildGraph(results); + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + if (success) { + statement.getConnection().cleanUp(); + } else { + statement.getConnection().errorCleanUp(); + } + } + } + + protected DataObject buildGraph(List results) throws SQLException { + + // Before we use the mappingModel, do some checking/updating. If + // inferrable information + // isn't specified, add it in. + + GraphBuilderMetadata gbmd = new GraphBuilderMetadata(results, configWrapper.getConfig(), + resultSetShape); + + // Create the DataGraph + DataGraph g = SDOUtil.createDataGraph(); + + // Create the root object + g.createRootObject(gbmd.getRootType()); + + SDOUtil.registerDataGraphTypes(g, gbmd.getDefinedTypes()); + + ChangeSummary summary = g.getChangeSummary(); + + ResultSetProcessor rsp = new ResultSetProcessor(g.getRootObject(), gbmd); + rsp.processResults(getStartRow(), getEndRow()); + + summary.beginLogging(); + + return g.getRootObject(); + } + + + protected int getStartRow() { + return startRow; + } + + protected int getEndRow() { + return endRow; + } + + protected void setStartRow(int startRow) { + this.startRow = startRow; + } + + protected void setEndRow(int endRow) { + this.endRow = endRow; + } + + + protected void enablePaging() { + statement.enablePaging(); + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ResultSetShape.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ResultSetShape.java new file mode 100644 index 0000000000..861b292bef --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/ResultSetShape.java @@ -0,0 +1,161 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.List; + +import org.apache.tuscany.das.rdb.config.Config; +import org.apache.tuscany.das.rdb.config.ResultDescriptor; +import org.apache.tuscany.das.rdb.graphbuilder.schema.ResultSetTypeMap; + +import commonj.sdo.Type; +import commonj.sdo.helper.TypeHelper; + +/** + * Describes the structure of the result set returned from + * execution of a SELECT statement. This description is typcially + * not required since the shape can be retreived from the JDBC + * ResultSetMetadata. However, some platforms such as Oracle do not + * support fully suport ResultSetMedata. + * <p> + * There may also be a performance boost when using this interface. + * + * + */ +public class ResultSetShape { + + private final String[] columns; + + private final String[] tables; + + private final Type[] types; + + private final String[] schema;//JIRA-952 + //JIRA-952 + public ResultSetShape(ResultSetMetaData metadata, Config model) throws SQLException { + columns = new String[metadata.getColumnCount()]; + tables = new String[metadata.getColumnCount()]; + types = new Type[metadata.getColumnCount()]; + schema = new String[metadata.getColumnCount()]; + + ResultSetTypeMap typeMap = ResultSetTypeMap.INSTANCE; + for (int i = 1; i <= metadata.getColumnCount(); i++) { + if(model.isDatabaseSchemaNameSupported()){ + if(metadata.getSchemaName(i) != null && !metadata.getSchemaName(i).equals("")){ + //tables[i - 1] = metadata.getSchemaName(i)+"."+metadata.getTableName(i); + tables[i - 1] = metadata.getTableName(i); + schema[i - 1] = metadata.getSchemaName(i); + } + else{ + tables[i - 1] = metadata.getTableName(i); + schema[i - 1] = ""; + } + } + else{ + tables[i - 1] = metadata.getTableName(i); + schema[i - 1] = ""; + } + columns[i - 1] = metadata.getColumnName(i); + types[i - 1] = typeMap.getType(metadata.getColumnType(i), true); + } + } + + //JIRA-952 + public ResultSetShape(List resultDescriptor, Config model) { + TypeHelper helper = TypeHelper.INSTANCE; + int size = resultDescriptor.size(); + columns = new String[size]; + tables = new String[size]; + types = new Type[size]; + schema = new String[size]; + + for (int i = 0; i < size; i++) { + ResultDescriptor desc = (ResultDescriptor) resultDescriptor.get(i); + if(model.isDatabaseSchemaNameSupported()){ + if(desc.getSchemaName() != null && !desc.getSchemaName().equals("")){ + tables[i] = desc.getTableName(); + schema[i] = desc.getSchemaName(); + }else{ + tables[i] = desc.getTableName(); + schema[i] = ""; + } + + }else{ + tables[i] = desc.getTableName(); + schema[i] = ""; + } + columns[i] = desc.getColumnName(); + + int idx = desc.getColumnType().lastIndexOf('.'); + String uri = desc.getColumnType().substring(0, idx); + String typeName = desc.getColumnType().substring(idx + 1); + + types[i] = helper.getType(uri, typeName); + if (types[i] == null) { + throw new RuntimeException("Could not find type " + desc.getColumnType() + + " for column " + desc.getColumnName()); + } + } + + } + + public int getColumnCount() { + return columns.length; + } + + public String getTableName(int i) { + return tables[i - 1]; + } + + //JIRA-952 + public String getSchemaName(int i) { + return schema[i - 1]; + } + public String getColumnName(int i) { + return columns[i - 1]; + } + + public Type getColumnType(int i) { + return types[i - 1]; + } + + public String toString() { + StringBuffer result = new StringBuffer(); + result.append(" column/table/schema/type: "); + for (int i = 0; i < columns.length; i++) { + result.append(columns[i]); + result.append('\t'); + result.append(tables[i]); + result.append('\t'); + result.append(schema[i]); + result.append('\t'); + if (types[i] == null) { + result.append("null"); + } else { + result.append(types[i].getName()); + } + result.append('\n'); + } + + return result.toString(); + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/SDODataTypeHelper.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/SDODataTypeHelper.java new file mode 100644 index 0000000000..1038c9a99a --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/SDODataTypeHelper.java @@ -0,0 +1,109 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.sql.Types; + +import commonj.sdo.Type; + +public final class SDODataTypeHelper { + + private SDODataTypeHelper() { + + } + + public static int sqlTypeFor(Type sdoType) { + if (sdoType == null) { + return Types.OTHER; + } + + if (sdoType == SDODataTypes.BOOLEAN) { + return Types.BOOLEAN; + } else if (sdoType == SDODataTypes.STRING) { + return Types.VARCHAR; + } else if (sdoType == SDODataTypes.BYTE) { + return Types.TINYINT; + } else if (sdoType == SDODataTypes.BYTES) { + return Types.BINARY; + } else if (sdoType == SDODataTypes.CHARACTER) { + return Types.CHAR; + } else if (sdoType == SDODataTypes.DATE) { + return Types.DATE; + } else if (sdoType == SDODataTypes.DATETIME) { + return Types.DATE; + } else if (sdoType == SDODataTypes.DAY) { + return java.sql.Types.BINARY; + } else if (sdoType == SDODataTypes.DECIMAL) { + return java.sql.Types.DECIMAL; + } else if (sdoType == SDODataTypes.DOUBLE) { + return java.sql.Types.DOUBLE; + } else if (sdoType == SDODataTypes.DURATION) { + return java.sql.Types.VARCHAR; + } else if (sdoType == SDODataTypes.FLOAT) { + return java.sql.Types.REAL; + } else if (sdoType == SDODataTypes.INT) { + return java.sql.Types.INTEGER; + } else if (sdoType == SDODataTypes.INTEGER) { + return java.sql.Types.INTEGER; + } else if (sdoType == SDODataTypes.LONG) { + return java.sql.Types.BIGINT; + } else if (sdoType == SDODataTypes.MONTH) { + return java.sql.Types.VARCHAR; + } else if (sdoType == SDODataTypes.MONTHDAY) { + return java.sql.Types.VARCHAR; + } else if (sdoType == SDODataTypes.OBJECT) { + return java.sql.Types.JAVA_OBJECT; + } else if (sdoType == SDODataTypes.SHORT) { + return java.sql.Types.SMALLINT; + } else if (sdoType == SDODataTypes.STRING) { + return java.sql.Types.VARCHAR; + } else if (sdoType == SDODataTypes.STRINGS) { + return java.sql.Types.OTHER; + } else if (sdoType == SDODataTypes.TIME) { + return java.sql.Types.VARCHAR; + } else if (sdoType == SDODataTypes.URI) { + return java.sql.Types.VARCHAR; + } else if (sdoType == SDODataTypes.YEAR) { + return java.sql.Types.VARCHAR; + } else if (sdoType == SDODataTypes.YEARMONTH) { + return java.sql.Types.VARCHAR; + } else if (sdoType == SDODataTypes.YEARMONTHDAY) { + return java.sql.Types.VARCHAR; + } else if (sdoType == SDODataTypes.BOOLEANOBJECT) { + return java.sql.Types.BOOLEAN; + } else if (sdoType == SDODataTypes.BYTEOBJECT) { + return java.sql.Types.TINYINT; + } else if (sdoType == SDODataTypes.CHARACTEROBJECT) { + return java.sql.Types.CHAR; + } else if (sdoType == SDODataTypes.DOUBLEOBJECT) { + return java.sql.Types.DOUBLE; + } else if (sdoType == SDODataTypes.FLOATOBJECT) { + return java.sql.Types.REAL; + } else if (sdoType == SDODataTypes.INTEGEROBJECT) { + return java.sql.Types.INTEGER; + } else if (sdoType == SDODataTypes.LONGOBJECT) { + return java.sql.Types.BIGINT; + } else if (sdoType == SDODataTypes.SHORTOBJECT) { + return java.sql.Types.SMALLINT; + } else { + throw new RuntimeException("Not a valid SDO Type " + sdoType); + } + + } +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/SDODataTypes.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/SDODataTypes.java new file mode 100644 index 0000000000..2052950272 --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/SDODataTypes.java @@ -0,0 +1,98 @@ +/* + * 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.tuscany.das.rdb.impl; + +import commonj.sdo.Type; +import commonj.sdo.helper.TypeHelper; + +/** + * Defines SDO data types. This is used primalirly to type stored procedure OUT parameters. + * + */ +public class SDODataTypes { + + public static final TypeHelper TYPE_HELPER = TypeHelper.INSTANCE; + + public static final Type BOOLEAN = TYPE_HELPER.getType("commonj.sdo", "Boolean"); + + public static final Type BYTE = TYPE_HELPER.getType("commonj.sdo", "Byte"); + + public static final Type BYTES = TYPE_HELPER.getType("commonj.sdo", "Bytes"); + + public static final Type CHARACTER = TYPE_HELPER.getType("commonj.sdo", "Character"); + + public static final Type DATE = TYPE_HELPER.getType("commonj.sdo", "Date"); + + public static final Type DATETIME = TYPE_HELPER.getType("commonj.sdo", "Date"); + + public static final Type DAY = TYPE_HELPER.getType("commonj.sdo", "Date"); + + public static final Type DECIMAL = TYPE_HELPER.getType("commonj.sdo", "Float"); + + public static final Type DOUBLE = TYPE_HELPER.getType("commonj.sdo", "Double"); + + public static final Type DURATION = TYPE_HELPER.getType("commonj.sdo", "Date"); + + public static final Type FLOAT = TYPE_HELPER.getType("commonj.sdo", "Float"); + + public static final Type INT = TYPE_HELPER.getType("commonj.sdo", "Int"); + + public static final Type INTEGER = TYPE_HELPER.getType("commonj.sdo", "Integer"); + + public static final Type LONG = TYPE_HELPER.getType("commonj.sdo", "Long"); + + public static final Type MONTH = TYPE_HELPER.getType("commonj.sdo", "Date"); + + public static final Type MONTHDAY = TYPE_HELPER.getType("commonj.sdo", "Date"); + + public static final Type OBJECT = TYPE_HELPER.getType("commonj.sdo", "Object"); + + public static final Type SHORT = TYPE_HELPER.getType("commonj.sdo", "Short"); + + public static final Type STRING = TYPE_HELPER.getType("commonj.sdo", "String"); + + public static final Type STRINGS = TYPE_HELPER.getType("commonj.sdo", "String"); + + public static final Type TIME = TYPE_HELPER.getType("commonj.sdo", "Date"); + + public static final Type URI = TYPE_HELPER.getType("commonj.sdo", "String"); + + public static final Type YEAR = TYPE_HELPER.getType("commonj.sdo", "Date"); + + public static final Type YEARMONTH = TYPE_HELPER.getType("commonj.sdo", "Date"); + + public static final Type YEARMONTHDAY = TYPE_HELPER.getType("commonj.sdo", "Date"); + + public static final Type BOOLEANOBJECT = TYPE_HELPER.getType("commonj.sdo", "BooleanObject"); + + public static final Type BYTEOBJECT = TYPE_HELPER.getType("commonj.sdo", "ByteObject"); + + public static final Type CHARACTEROBJECT = TYPE_HELPER.getType("commonj.sdo", "CharacterObject"); + + public static final Type DOUBLEOBJECT = TYPE_HELPER.getType("commonj.sdo", "DoubleObject"); + + public static final Type FLOATOBJECT = TYPE_HELPER.getType("commonj.sdo", "FloatObject"); + + public static final Type INTEGEROBJECT = TYPE_HELPER.getType("commonj.sdo", "IntObject"); + + public static final Type LONGOBJECT = TYPE_HELPER.getType("commonj.sdo", "LongObject"); + + public static final Type SHORTOBJECT = TYPE_HELPER.getType("commonj.sdo", "ShortObject"); + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/SPCommandImpl.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/SPCommandImpl.java new file mode 100644 index 0000000000..e34069822d --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/SPCommandImpl.java @@ -0,0 +1,100 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.sql.SQLException; +import java.util.Iterator; +import java.util.List; + +import org.apache.log4j.Logger; +import org.apache.tuscany.das.rdb.config.Parameter; +import org.apache.tuscany.das.rdb.config.wrapper.MappingWrapper; + +import commonj.sdo.DataObject; +import commonj.sdo.Type; +import commonj.sdo.helper.TypeHelper; + +public class SPCommandImpl extends ReadCommandImpl { + private final Logger logger = Logger.getLogger(SPCommandImpl.class); + + public SPCommandImpl(String sqlString, MappingWrapper config, List params) { + super(sqlString, config, null); + Iterator i = params.iterator(); + while (i.hasNext()) { + Parameter p = (Parameter) i.next(); + + int index = p.getColumnType().lastIndexOf('.'); + String pkg = p.getColumnType().substring(0, index); + String typeName = p.getColumnType().substring(index + 1); + + Type sdoType = TypeHelper.INSTANCE.getType(pkg, typeName); + + int direction = ParameterImpl.IN; + if ("OUT".equalsIgnoreCase(p.getDirection())) { + direction = ParameterImpl.OUT; + } else if ("INOUT".equalsIgnoreCase(p.getDirection())) { + direction = ParameterImpl.IN_OUT; + } + parameters.findOrCreateParameterWithIndex(p.getIndex(), direction, sdoType); + } + + } + + public DataObject executeQuery() { + + boolean success = false; + try { + List results = statement.executeCall(parameters); + success = true; + + return buildGraph(results); + } catch (SQLException e) { + if (this.logger.isDebugEnabled()) { + this.logger.debug(e); + } + + throw new RuntimeException(e); + } finally { + if (success) { + statement.getConnection().cleanUp(); + } else { + statement.getConnection().errorCleanUp(); + } + } + } + + public void execute() { + + boolean success = false; + try { + statement.executeUpdateCall(parameters); + success = true; + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + if (success) { + statement.getConnection().cleanUp(); + } else { + statement.getConnection().errorCleanUp(); + } + } + + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/Statement.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/Statement.java new file mode 100644 index 0000000000..cc637e460a --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/Statement.java @@ -0,0 +1,233 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.sql.CallableStatement; +import java.sql.ParameterMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.apache.log4j.Logger; + +// TODO - Can use some refactoring. Much code is duplicated in "execute" methods +public class Statement { + + protected final String queryString; + + protected ConnectionImpl jdbcConnection; + + private final Logger logger = Logger.getLogger(Statement.class); + + private PreparedStatement preparedStatement; + + private boolean isPaging; + + public Statement(String sqlString) { + this.queryString = sqlString; + } + + public List executeQuery(Parameters parameters) throws SQLException { + + PreparedStatement ps = getPreparedStatement(new String[0]); + ps = setParameters(ps, parameters); + ResultSet rs = ps.executeQuery(); + + return Collections.singletonList(rs); + } + + public List executeCall(Parameters parameters) throws SQLException { + + CallableStatement cs = jdbcConnection.prepareCall(queryString); + + Iterator inParams = parameters.inParams().iterator(); + while (inParams.hasNext()) { + ParameterImpl param = (ParameterImpl) inParams.next(); + cs.setObject(param.getIndex(), param.getValue()); + } + + // register out parameters + Iterator outParams = parameters.outParams().iterator(); + while (outParams.hasNext()) { + ParameterImpl param = (ParameterImpl) outParams.next(); + if (this.logger.isDebugEnabled()) { + this.logger.debug("Registering parameter " + param.getName()); + } + + cs.registerOutParameter(param.getIndex(), SDODataTypeHelper.sqlTypeFor(param.getType())); + } + + // Using execute because Derby does not currenlty support + // executeQuery + // for SP + cs.execute(); + List results = new ArrayList(); + results.add(cs.getResultSet()); + while (cs.getMoreResults(java.sql.Statement.KEEP_CURRENT_RESULT)) { + results.add(cs.getResultSet()); + } + + Iterator i = parameters.outParams().iterator(); + while (i.hasNext()) { + ParameterImpl param = (ParameterImpl) i.next(); + param.setValue(cs.getObject(param.getIndex())); + } + + return results; + + } + + public void executeUpdateCall(Parameters parameters) throws SQLException { + CallableStatement cs = jdbcConnection.prepareCall(queryString); + + Iterator inParams = parameters.inParams().iterator(); + while (inParams.hasNext()) { + ParameterImpl param = (ParameterImpl) inParams.next(); + cs.setObject(param.getIndex(), param.getValue()); + } + + // register out parameters + Iterator outParams = parameters.outParams().iterator(); + while (outParams.hasNext()) { + ParameterImpl param = (ParameterImpl) outParams.next(); + + if (this.logger.isDebugEnabled()) { + this.logger.debug("Registering parameter " + param.getName()); + } + + cs.registerOutParameter(param.getIndex(), SDODataTypeHelper.sqlTypeFor(param.getType())); + } + + cs.execute(); + + Iterator out = parameters.outParams().iterator(); + while (out.hasNext()) { + ParameterImpl param = (ParameterImpl) out.next(); + param.setValue(cs.getObject(param.getIndex())); + } + + } + + public int executeUpdate(Parameters parameters, String[] generatedKeys) throws SQLException { + return executeUpdate(getPreparedStatement(generatedKeys), parameters); + } + + public int executeUpdate(Parameters parameters) throws SQLException { + return executeUpdate(parameters, new String[0]); + } + + /** + * TODO - We need to look at using specific ps.setXXX methods when a type + * has been specified and try setObject otherwise. + */ + private int executeUpdate(PreparedStatement ps, Parameters parameters) throws SQLException { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Executing statement " + queryString); + } + + Iterator i = parameters.inParams().iterator(); + while (i.hasNext()) { + ParameterImpl param = (ParameterImpl) i.next(); + + Object value = param.getValue(); + if (this.logger.isDebugEnabled()) { + this.logger.debug("Setting parameter " + param.getIndex() + " to " + value); + } + + if (value == null) { + if (param.getType() == null) { + try { + ParameterMetaData pmd = ps.getParameterMetaData(); + ps.setNull(param.getIndex(), pmd.getParameterType(param.getIndex())); + } catch (SQLException ex) { + ps.setNull(param.getIndex(), SDODataTypeHelper.sqlTypeFor(null)); + } + } else { + ps.setNull(param.getIndex(), SDODataTypeHelper.sqlTypeFor(param.getType())); + } + } else { + ps.setObject(param.getIndex(), value); + } + } + return ps.executeUpdate(); + } + + protected PreparedStatement setParameters(PreparedStatement ps, Parameters parameters) throws SQLException { + Iterator i = parameters.inParams().iterator(); + while (i.hasNext()) { + ParameterImpl param = (ParameterImpl) i.next(); + ps.setObject(param.getIndex(), param.getValue()); + } + return ps; + } + + public void setConnection(ConnectionImpl jdbcConnection) { + this.jdbcConnection = jdbcConnection; + } + + public ConnectionImpl getConnection() { + return this.jdbcConnection; + } + + private PreparedStatement getPreparedStatement(String[] returnKeys) throws SQLException { + + if (preparedStatement == null) { + if (isPaging) { + preparedStatement = jdbcConnection.preparePagedStatement(queryString); + } else { + preparedStatement = jdbcConnection.prepareStatement(queryString, returnKeys); + } + } + + return preparedStatement; + } + + public Integer getGeneratedKey() throws SQLException { + + if (getConnection().useGetGeneratedKeys()) { + ResultSet rs = preparedStatement.getGeneratedKeys(); + if (rs.next()) { + return Integer.valueOf(rs.getInt(1)); + } + } + + return null; + } + + protected void enablePaging() { + isPaging = true; + } + + public void close() { + + if (this.preparedStatement != null) { + try { + preparedStatement.close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/UpdateCommandImpl.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/UpdateCommandImpl.java new file mode 100644 index 0000000000..11a78bb5d1 --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/UpdateCommandImpl.java @@ -0,0 +1,34 @@ +/* + * 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.tuscany.das.rdb.impl; + +import org.apache.tuscany.das.rdb.config.Update; + +public class UpdateCommandImpl extends WriteCommandImpl { + + public UpdateCommandImpl(String sqlString) { + super(sqlString); + } + + public UpdateCommandImpl(Update update) { + super(update.getSql()); + addParameters(update.getParameters()); + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/UpdateList.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/UpdateList.java new file mode 100644 index 0000000000..e7bb58698c --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/UpdateList.java @@ -0,0 +1,45 @@ +/* + * 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.tuscany.das.rdb.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Updates don't have to be sorted, so this class is a simple wrapper of ArrayList. + * + */ +public class UpdateList { + + private List updates = new ArrayList(); + + public UpdateList() { + super(); + } + + public void add(ChangeOperation c) { + updates.add(c); + } + + public Collection getSortedList() { + return updates; + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/UpdateOperation.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/UpdateOperation.java new file mode 100644 index 0000000000..1bcf3441b6 --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/UpdateOperation.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.tuscany.das.rdb.impl; + + +import commonj.sdo.DataObject; + + +public class UpdateOperation extends ChangeOperation { + + public UpdateOperation(UpdateCommandImpl command, DataObject changedObject, String id) { + super(command, changedObject); + this.propagatedID = id; + } + +} diff --git a/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/WriteCommandImpl.java b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/WriteCommandImpl.java new file mode 100644 index 0000000000..ae082976eb --- /dev/null +++ b/das-java/tags/1.0-incubating-beta1-rc4/rdb/src/main/java/org/apache/tuscany/das/rdb/impl/WriteCommandImpl.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.tuscany.das.rdb.impl; + +import java.sql.SQLException; +import java.util.StringTokenizer; + +import org.apache.tuscany.das.rdb.config.Config; + +import commonj.sdo.DataObject; + +public abstract class WriteCommandImpl extends CommandImpl { + + public WriteCommandImpl(String sqlString) { + super(sqlString); + } + + public void execute() { + + boolean success = false; + try { + basicExecute(); + success = true; + } finally { + if (success) { + statement.getConnection().cleanUp(); + } else { + statement.getConnection().errorCleanUp(); + } + } + + } + + public void basicExecute() { + try { + statement.executeUpdate(parameters); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public DataObject executeQuery() { + throw new UnsupportedOperationException(); + } + + public Config getMappingModel() { + return configWrapper.getConfig(); + } + + public String toString() { + + StringBuffer buffer = new StringBuffer(); + buffer.append("\nSQL: " + statement.queryString); + + return buffer.toString(); + } + + public int getGeneratedKey() { + throw new RuntimeException("No generated key is available"); + } + + public void addParameters(String parameters) { + StringTokenizer tokenizer = new StringTokenizer(parameters); + for (int idx = 1; tokenizer.hasMoreTokens(); idx++) { + ParameterImpl p = new ParameterImpl(); + p.setName(tokenizer.nextToken()); + p.setIndex(idx); + addParameter(p); + } + } + +} |