/* * 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.config.wrapper; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; import org.apache.log4j.Logger; import org.apache.tuscany.das.rdb.config.Column; import org.apache.tuscany.das.rdb.config.Command; 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.ConnectionProperties; import org.apache.tuscany.das.rdb.config.Create; import org.apache.tuscany.das.rdb.config.Delete; import org.apache.tuscany.das.rdb.config.KeyPair; import org.apache.tuscany.das.rdb.config.Parameters; import org.apache.tuscany.das.rdb.config.Relationship; import org.apache.tuscany.das.rdb.config.Table; import org.apache.tuscany.das.rdb.config.Update; import commonj.sdo.Property; public class MappingWrapper { private static final ConfigFactory FACTORY = ConfigFactory.INSTANCE; private final Logger logger = Logger.getLogger(MappingWrapper.class); private Config config; // TUSCANY-2288 private List insertOrder; private List deleteOrder; private Set rootTableNames; // -- public MappingWrapper() { config = FACTORY.createConfig(); //JIRA-952 this.checkSchemaNameSupport(); } //JIRA-952 - check if there is any entry with no schemaName when support is ON public void checkSchemaNameSupport(){ if(config.isDatabaseSchemaNameSupported()){ List tableList = config.getTable(); for(int i=0; itype, if one is available in Config*/ public Collection getRelationshipsByChildTable(String name) { Table table = getTableByTypeName(name); if(table != null) { if(config.isDatabaseSchemaNameSupported()) { name = table.getSchemaName()+"."+table.getTableName(); } else { name = table.getTableName(); } } //table can be null, when no in Config and Query based Dynamic Types are used during query List results = new ArrayList(); if (config != null) { Iterator i = getConfig().getRelationship().iterator(); while (i.hasNext()) { Relationship r = (Relationship) i.next(); if (name.equals(r.getForeignKeyTable())) { results.add(r); } } } return results; } public Set getRootTableNames() { if (this.logger.isDebugEnabled()) { this.logger.debug("Getting root tables"); } if (rootTableNames == null) { rootTableNames = new HashSet(); if (config == null) return rootTableNames; // parse all relationships Set allParents = new HashSet(); Set allChildren = new HashSet(); Iterator i = getConfig().getRelationship().iterator(); while (i.hasNext()) { Relationship r = (Relationship) i.next(); String parent = r.getPrimaryKeyTable(); String child = r.getForeignKeyTable(); if (parent.equals(child)) { // self-relationship // do not add to all children list to allow root detection allParents.add(parent); } else { allParents.add(parent); allChildren.add(child); } } // find roots (depth 0) // roots are tables that are present in the parents set, but not in the children set for (Iterator itParents = allParents.iterator(); itParents.hasNext(); ) { String parent = (String) itParents.next(); if (!allChildren.contains(parent)) { rootTableNames.add(parent); } } } if (this.logger.isDebugEnabled()) { this.logger.debug(rootTableNames); } return rootTableNames; } // TUSCANY-2288 public List getInsertOrder() { if (this.logger.isDebugEnabled()) { this.logger.debug("Getting insert order"); } if (insertOrder == null) { insertOrder = new ArrayList(); if (config == null) return insertOrder; // correct insert order: tables sorted by ascending depth // parse all relationships Set allParents = new HashSet(); Set allChildren = new HashSet(); Map parentToChild = new HashMap(); Iterator i = getConfig().getRelationship().iterator(); while (i.hasNext()) { Relationship r = (Relationship) i.next(); String parent = r.getPrimaryKeyTable(); String child = r.getForeignKeyTable(); if (parent.equals(child)) { // self-relationship // do not add to all children list to allow root detection allParents.add(parent); Set children = (Set) parentToChild.get(parent); if (children == null) { children = new HashSet(); parentToChild.put(parent, children); } children.add(child); } else { allParents.add(parent); allChildren.add(child); Set children = (Set) parentToChild.get(parent); if (children == null) { children = new HashSet(); parentToChild.put(parent, children); } children.add(child); } } // build list of tables ordered by depth List depthList = new ArrayList(); // find roots (depth 0) // roots are tables that are present in the parents set, but not in the children set Set roots = new HashSet(); for (Iterator itParents = allParents.iterator(); itParents.hasNext(); ) { String parent = (String) itParents.next(); if (!allChildren.contains(parent)) { roots.add(parent); } } // traverse table graph to populate depth list traverseTableGraph(roots, 0, parentToChild, depthList, new ArrayList()); // build insert order from depth list for (Iterator itDepths = depthList.iterator(); itDepths.hasNext(); ) { Set tables = (Set) itDepths.next(); insertOrder.addAll(tables); } } if (this.logger.isDebugEnabled()) { this.logger.debug(insertOrder); } return insertOrder; } private void traverseTableGraph(Set parents, int parentDepth, Map parentToChild, List depthList, List branch) { int childDepth = parentDepth + 1; // expand depth list if necessary for (int i = depthList.size() - 1; i < parentDepth; i++) { Set tables = new HashSet(); depthList.add(tables); } // loop thru parents for (Iterator itParents = parents.iterator(); itParents.hasNext(); ) { String parent = (String) itParents.next(); if (branch.contains(parent)) { // we found a cycle // stop traversing branch to avoid infinite loop if depth greater than threshold break; } // add parent to depth list addTableToDepthList(parent, parentDepth, depthList); // make recursive call on children Set children = (Set) parentToChild.get(parent); if (children != null && children.size() > 0) { List parentBranch = new ArrayList(); parentBranch.addAll(branch); parentBranch.add(parent); traverseTableGraph(children, childDepth, parentToChild, depthList, parentBranch); } } } private void addTableToDepthList(String table, int depth, List depthList) { // in this method, keep in mind that the same table can appear multiple times at multiple depths inside the table graph // check if table is already somewhere in depth list int currentDepth = getTableDepth(table, depthList); if (currentDepth == -1) { // table not in depth list // add it Set tables = (Set) depthList.get(depth); tables.add(table); } else if (currentDepth < depth) { // table already in depth list, at a lower depth // the table should only be present once, at the greatest possible depth // replace table at the new depth Set tables = (Set) depthList.get(currentDepth); tables.remove(table); tables = (Set) depthList.get(depth); tables.add(table); } else { // table already in depth list, at a greater or same depth // nothing to do, since the table should only be present once, at the greatest possible depth } } private int getTableDepth(String table, List depthList) { int depth = -1; // loop thru depth list int count = depthList.size(); for (int i = 0; i < count; i++) { Set tables = (Set) depthList.get(i); if (tables != null && tables.contains(table)) { depth = i; break; } } return depth; } public List getDeleteOrder() { if (deleteOrder == null) { deleteOrder = new ArrayList(); deleteOrder.addAll(getInsertOrder()); Collections.reverse(deleteOrder); } return deleteOrder; } // -- //JIRA-952 public void addConverter(String name, String converter) { QualifiedColumn column = new QualifiedColumn(name, this.config.isDatabaseSchemaNameSupported()); Table t = null; t = findOrCreateTable(column); Column c = findOrCreateColumn(t, column.getColumnName()); c.setConverterClassName(converter); } public String getConverter(String tableName, String columnName) { Table t = getTable(tableName); Column c = getColumn(t, columnName); if (c != null) { return c.getConverterClassName(); } return null; } public Map getConverters(Table table) { Map converters = new HashMap(); Iterator columns = table.getColumn().iterator(); while (columns.hasNext()) { Column c = (Column) columns.next(); if (c.getConverterClassName() != null) { String property = c.getPropertyName(); if (property == null) { property = c.getColumnName(); } converters.put(property, c.getConverterClassName()); } } return converters; } public Relationship getRelationshipByReference(Property ref) { Iterator i = config.getRelationship().iterator(); while (i.hasNext()) { Relationship r = (Relationship) i.next(); if (ref.getName().equals(r.getName())) { if (getTableTypeName(r.getPrimaryKeyTable()).equals(ref.getContainingType().getName())) return r; } else if(ref.getOpposite().getName().equals(r.getName())) { if (getTableTypeName(r.getForeignKeyTable()).equals(ref.getContainingType().getName())) return r; } } throw new RuntimeException("Could not find relationship " + ref.getName() + " in the configuration"); } public Relationship getRelationshipByName(String name) { Iterator i = config.getRelationship().iterator(); while (i.hasNext()) { Relationship r = (Relationship) i.next(); if (name.equals(r.getName())) { return r; } } throw new RuntimeException("Could not find relationship " + name + " in the configuration"); } public void addUpdateStatement(Table table, String statement, Parameters parameters) { Update update = ConfigFactory.INSTANCE.createUpdate(); update.setSql(statement); update.setParameters(parameters); table.setUpdate(update); } public void addDeleteStatement(Table table, String statement, Parameters parameters) { Delete delete = ConfigFactory.INSTANCE.createDelete(); delete.setSql(statement); delete.setParameters(parameters); table.setDelete(delete); } public void addCreateStatement(Table table, String statement, Parameters parameters) { Create create = ConfigFactory.INSTANCE.createCreate(); create.setSql(statement); create.setParameters(parameters); table.setCreate(create); } //JIRA-948 support for driver manager connection public void addConnectionInfo(String dataSourceName, boolean managedtx){ ConnectionInfo info = ConfigFactory.INSTANCE.createConnectionInfo(); info.setDataSource(dataSourceName); info.setManagedtx(managedtx); config.setConnectionInfo(info); } public void addConnectionInfo(String driverClass, String connectionURL, String user, String password, int loginTimeout) { ConnectionInfo info = ConfigFactory.INSTANCE.createConnectionInfo(); ConnectionProperties connectionProperties = ConfigFactory.INSTANCE.createConnectionProperties(); connectionProperties.setDriverClass(driverClass); connectionProperties.setDatabaseURL(connectionURL); connectionProperties.setUserName(user); connectionProperties.setPassword(password); connectionProperties.setLoginTimeout(loginTimeout); info.setConnectionProperties(connectionProperties); config.setConnectionInfo(info); } //JIRA-948 end public Command addCommand(String name, String sql, String kind) { Command cmd = ConfigFactory.INSTANCE.createCommand(); cmd.setName(name); cmd.setKind(kind); cmd.setSQL(sql); config.getCommand().add(cmd); return cmd; } //JIRA-952 public void addImpliedPrimaryKey(String schemaName, String tableName, String columnName) { Table t = findOrCreateTable(schemaName, tableName);//JIRA-952 Iterator i = t.getColumn().iterator(); boolean hasPK = false; while (i.hasNext()) { Column c = (Column) i.next(); if (c.isPrimaryKey()) { hasPK = true; } } if (!hasPK) { Column c = findOrCreateColumn(t, columnName); c.setPrimaryKey(true); } } }