All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.plasma.text.ddl.DDLModelAssembler Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version
/**
 *         PlasmaSDO™ License
 * 
 * This is a community release of PlasmaSDO™, a dual-license 
 * Service Data Object (SDO) 2.1 implementation. 
 * This particular copy of the software is released under the 
 * version 2 of the GNU General Public License. PlasmaSDO™ was developed by 
 * TerraMeta Software, Inc.
 * 
 * Copyright (c) 2013, TerraMeta Software, Inc. All rights reserved.
 * 
 * General License information can be found below.
 * 
 * This distribution may include materials developed by third
 * parties. For license and attribution notices for these
 * materials, please refer to the documentation that accompanies
 * this distribution (see the "Licenses for Third-Party Components"
 * appendix) or view the online documentation at 
 * .
 *  
 */
package org.plasma.text.ddl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.plasma.config.DataStoreType;
import org.plasma.config.PlasmaConfig;
import org.plasma.sdo.DataType;
import org.plasma.sdo.PlasmaProperty;
import org.plasma.sdo.PlasmaType;
import org.plasma.sdo.helper.PlasmaTypeHelper;
import org.plasma.sdo.profile.KeyType;
import org.plasma.sdo.repository.Class_;
import org.plasma.sdo.repository.Enumeration;
import org.plasma.sdo.repository.EnumerationLiteral;
import org.plasma.sdo.repository.Namespace;
import org.plasma.sdo.repository.OpaqueBehavior;
import org.plasma.sdo.repository.PlasmaRepository;

import commonj.sdo.Property;
import commonj.sdo.Type;

public class DDLModelAssembler {
	private static Log log = LogFactory.getLog(DDLModelAssembler.class);

	private Schemas schemas;
	// maps namespace physical names to maps of type physical names to types
	private Map> schemaMap = new HashMap>();
	
	// type physical names to namespace physical names
	private Map reverseSchemaMap = new HashMap();
	
	public DDLModelAssembler() {
		this(PlasmaRepository.getInstance().getAllNamespaces());
	}
	
	public DDLModelAssembler(String[] namespaces) {
		this(resultList(namespaces)); 
	}
	
	private static List resultList(String[] namespaces) {
		List result = new ArrayList();
		Map map = new HashMap();
		for (String uri : namespaces)
			map.put(uri, uri);
		for (Namespace namespace : PlasmaRepository.getInstance().getAllNamespaces()) {
			if (map.containsKey(namespace.getUri()))
				result.add(namespace);
		}
		return result;
	}
	
	public DDLModelAssembler(List namespaces) {
		
		schemas = new Schemas();
		// load maps
    	for (Namespace namespace : namespaces) {
    		log.debug("processing namespace: " + namespace.getUri());
    		if (!PlasmaConfig.getInstance().hasNamespace(DataStoreType.RDBMS))
    		{
        		log.debug("ignoring non "+DataStoreType.RDBMS.name()+" namespace: " + namespace.getUri());
    			continue;     			
    		}
    		// FIXME: Cassandra check
    		
        	List types = PlasmaTypeHelper.INSTANCE.getTypes(namespace.getUri());
        	for (Type type : types) {
        		PlasmaType plasmaType = (PlasmaType)type;
        		String typePhysicalName = null;
        		if (plasmaType.getPhysicalName() == null || plasmaType.getPhysicalName().length() == 0) {
        			typePhysicalName = this.derivePhysicalName(plasmaType);
        		}
        		else
        			typePhysicalName = plasmaType.getPhysicalName();
        		String namespacePhysicalName = null;
        		if (namespace.getPhysicalName() == null || namespace.getPhysicalName().trim().length() == 0) {
        			namespacePhysicalName = this.derivePhysicalName(namespace);
        		}
        		else
        			namespacePhysicalName = namespace.getPhysicalName();
        		Map typeMap = schemaMap.get(namespacePhysicalName);
        		if (typeMap == null) {
        			typeMap = new HashMap();
        			schemaMap.put(namespacePhysicalName, typeMap);
        		}
        		typeMap.put(typePhysicalName, plasmaType); 
        		reverseSchemaMap.put(typePhysicalName, namespacePhysicalName);
        	}
    	}
    	
    	// create
    	for (String schemaName : schemaMap.keySet()) {
    		log.debug("creating schema: " + schemaName);
       		Schema schema = createSchema(schemaName);
       	    Map typeMap = schemaMap.get(schemaName);
    		for (PlasmaType type : typeMap.values()) {
    			if (type.isAbstract()) {
    				if (log.isDebugEnabled())
    					log.debug("skipping abstract type, " + type);
    				continue;
    			}
    			
        		Table table = createTable(schema, type);
        		schema.getTables().add(table);
        		
        		
        		List properties = type.getProperties(); // returns all base type(s) props as well
        		Map map = new HashMap();
        		for (Property p : properties)
        			map.put(p, p);
        		
        		createColumns(schema, table, type, map.values());
        		createPriKey(table, map.values());
        		
        		Class_ repositoryClass = (Class_)type.getClassifier();
        		List ddlBehaviors = repositoryClass.getOpaqueBehaviors("DDL");
        		createBehaviors(table, ddlBehaviors);
        		List sqlBehaviors = repositoryClass.getOpaqueBehaviors("SQL");
        		createBehaviors(table, sqlBehaviors);
        		
        		createForeignConstraints(table, type, map.values());
        		createUniqueConstraints(table, map.values());
        		createCheckConstraints(table, map.values());
        		createIndexes(table, map.values());
    		}
    	}
	}
			
	private void createIndexes(Table table, Collection properties)
	{
		int i = 1;
		for (Property prop : properties) {
			PlasmaProperty plasmaProperty = (PlasmaProperty)prop;
			if (plasmaProperty.getPhysicalName() == null)
				continue;
			if (plasmaProperty.getType().isDataType())
				continue;
			
			Index index = new Index();
			index.setName("I_" + table.getName() + String.valueOf(i));
			index.setColumn(plasmaProperty.getPhysicalName());
			table.getIndices().add(index);
			i++;
		}		
	}
	
	private void createCheckConstraints(Table table, Collection properties)
	{
		int i = 1;
		for (Property prop : properties) {
			PlasmaProperty plasmaProperty = (PlasmaProperty)prop;
			if (plasmaProperty.getPhysicalName() == null)
				continue;
			
			if (!plasmaProperty.getType().isDataType())
				continue;
			if (plasmaProperty.getRestriction() == null)
				continue;			
			
			Check check = new Check();
			check.setName("CK_" + table.getName() + "_" + String.valueOf(i));
			check.setColumn(plasmaProperty.getPhysicalName());
			table.getChecks().add(check);
			Enumeration restriction = plasmaProperty.getRestriction();
			for (EnumerationLiteral lit : restriction.getOwnedLiteral()) {
				check.getValues().add(lit.getPhysicalName());
			}
			i++;
		}		
	}
	
	private void createUniqueConstraints(Table table, Collection properties)
	{
		int uniqueCount = 0;
		for (Property prop : properties) {
			PlasmaProperty plasmaProperty = (PlasmaProperty)prop;
			if (plasmaProperty.getPhysicalName() == null)
				continue;
			if (plasmaProperty.getKey() != null && 
				plasmaProperty.getKey().getType().ordinal() == KeyType.primary.ordinal()) {
				continue; // already unique
			}
			
			Boolean isUnique = (Boolean)plasmaProperty.get(PlasmaProperty.INSTANCE_PROPERTY_BOOLEAN_ISUNIQUE);
		    if (isUnique != null && isUnique.booleanValue())
		    	uniqueCount++;
		}
		
		if (uniqueCount > 0) {
			Unique unique = new Unique();
			unique.setName("UK_" + table.getName());
			table.getUniques().add(unique);
			
			int i = 1;
			for (Property prop : properties) {
				PlasmaProperty plasmaProperty = (PlasmaProperty)prop;
				if (plasmaProperty.getPhysicalName() == null)
					continue;
				if (plasmaProperty.getKey() != null && 
					plasmaProperty.getKey().getType().ordinal() == KeyType.primary.ordinal()) {
					continue; // already unique
				}
				Boolean isUnique = (Boolean)plasmaProperty.get(PlasmaProperty.INSTANCE_PROPERTY_BOOLEAN_ISUNIQUE);
			    if (isUnique == null || !isUnique.booleanValue())
					continue;
			    On on = new On();
			    on.setColumn(plasmaProperty.getPhysicalName());
			    unique.getOns().add(on);
				i++;
			}		
		}		
	}
	
	private void createForeignConstraints(Table table, PlasmaType plasmaType, 
			Collection properties)
	{
		int i = 1;
		for (Property prop : properties) {
			PlasmaProperty plasmaProperty = (PlasmaProperty)prop;
			if (plasmaProperty.getType().isDataType())
				continue; // only ref props
			if (plasmaProperty.isMany())
				continue; // only singular props
			
			String physicalName = null;
			if (plasmaProperty.getPhysicalName() == null) {
				log.warn("no physical name found for singular property, "
						+ plasmaProperty.getContainingType().getURI() + "#"
						+ plasmaProperty.getContainingType().getName() + "."
						+ plasmaProperty.getName() + " - deriving");
				physicalName = this.derivePhysicalName(plasmaProperty);
			}	
			else
				physicalName = plasmaProperty.getPhysicalName();
			
			Fk fk = new Fk();
			fk.setName("FK_" + table.getName() + String.valueOf(i));
			fk.setColumn(physicalName);
			
		    Type oppositeType = plasmaProperty.getType();
			if (!oppositeType.isAbstract()) {
				String typePhysicalName = null;
				if (((PlasmaType)oppositeType).getPhysicalName() != null)
					typePhysicalName = ((PlasmaType)oppositeType).getPhysicalName();
				else
					typePhysicalName = this.derivePhysicalName((PlasmaType)oppositeType);
				String schemaPhysicalname = this.reverseSchemaMap.get(typePhysicalName);
				fk.setToTable(typePhysicalName);
				fk.setToSchema(schemaPhysicalname);
			}
			else // FIXME: collapse all references in abstract classes into subclass
			{
				String typePhysicalName = null;
				if (plasmaType.getPhysicalName() != null)
					typePhysicalName = plasmaType.getPhysicalName();
				else
					typePhysicalName = this.derivePhysicalName(plasmaType);
				String schemaPhysicalname = this.reverseSchemaMap.get(typePhysicalName);
				fk.setToTable(typePhysicalName);
				fk.setToSchema(schemaPhysicalname);
			}
			
			table.getFks().add(fk);
			i++;
		}		
	}
	
	private void createBehaviors(Table table, List behaviors)
	{
		for (OpaqueBehavior behavior : behaviors) {
			BehaviorType type = null;
			try {
			    type = BehaviorType.fromValue(behavior.getName().toLowerCase());
			}
			catch (IllegalArgumentException e) {
	    		StringBuilder buf = new StringBuilder();
	    		for (int i = 0; i < BehaviorType.values().length; i++) {
	    			if (i > 0)
	    				buf.append(", ");
	    			buf.append(BehaviorType.values()[i].value());
	    		}
				throw new DDLException("unknown behavior name '"
						+ behavior.getName()
						+ "' - expected one of ["
						+ buf.toString() + "]");
			}
			Behavior ddlBehavior = new Behavior();
			ddlBehavior.setType(type);
			ddlBehavior.setValue(behavior.getBody());
			if (!ddlBehavior.getValue().trim().endsWith(":")) {
				if (log.isDebugEnabled())
					log.debug("appending DDL statement terminator for '" + ddlBehavior.getType() + "'");				 
				ddlBehavior.setValue(ddlBehavior.getValue().trim() + ";");
			}
			table.getBehaviors().add(ddlBehavior);
		}		
	}
	
	private String derivePhysicalName(PlasmaProperty plasmaProperty) {
		String derivedPhysicalName = null;
	    if (plasmaProperty.getType().isDataType()) { 
	    	derivedPhysicalName = plasmaProperty.getName().toUpperCase();
	    }
	    else {
		    Type oppositeType = plasmaProperty.getType();
		    derivedPhysicalName = ((PlasmaType)oppositeType).getPhysicalName();	
		    if (derivedPhysicalName == null)
		    	derivedPhysicalName = derivePhysicalName((PlasmaType)oppositeType);
	    }
	    if (derivedPhysicalName == null || derivedPhysicalName.trim().length() == 0)
	    	throw new DDLException("could not derive physical name for property, " + plasmaProperty);
	    return derivedPhysicalName;
	}

	private String derivePhysicalName(PlasmaType plasmatype) {
		String derivedPhysicalName = plasmatype.getName().toUpperCase();
	    return derivedPhysicalName;
	}
	
	private String derivePhysicalName(Namespace namespace) {
		String derivedPhysicalName = namespace.getName().toUpperCase();
	    return derivedPhysicalName;
	}
	
	private void createColumns(Schema schema, Table table, PlasmaType plasmaType, 
			Collection properties)
	{
		for (Property prop : properties) {
			PlasmaProperty plasmaProperty = (PlasmaProperty)prop;
			if (plasmaProperty.isMany())
				continue;
			String derivedPhysicalName = null;
			if (plasmaProperty.getPhysicalName() == null) {
				log.warn("no physical name found for singular property, "
						+ plasmaProperty.getContainingType().getURI() + "#"
						+ plasmaProperty.getContainingType().getName() + "."
						+ plasmaProperty.getName() + " - deriving");
				derivedPhysicalName = derivePhysicalName(plasmaProperty);
			}	
			Column column = null;
			if (derivedPhysicalName == null) {
			    column = createColumn(schema, table,
					plasmaType,
					plasmaProperty);
			}
			else {
			    column = createColumn(schema, table,
					plasmaType,
					plasmaProperty, derivedPhysicalName);
			}
			table.getColumns().add(column);
		}		
	}
	
	private void createPriKey(Table table, Collection properties) {
		for (Property prop : properties) {
			PlasmaProperty plasmaProperty = (PlasmaProperty)prop;
			if (plasmaProperty.getPhysicalName() == null)
				continue;
		    if (!plasmaProperty.isKey(KeyType.primary))
				continue;

		    Pk pk = table.getPk();
		    if (pk == null) {
		        pk = createPk(table, plasmaProperty);
		        table.setPk(pk);
		    }
		    On on = new On();
		    on.setColumn(plasmaProperty.getPhysicalName());
			table.getPk().getOns().add(on);
		}		
	}
	
	private Pk createPk(Table table, PlasmaProperty plasmaProperty) {
		Pk pk = new Pk();
		pk.setName("PK_" + table.getName());
		return pk;
	}	
	
	private Column createColumn(Schema schema, Table table, PlasmaType plasmaType, 
			PlasmaProperty plasmaProperty) {
		return this.createColumn(schema, table, plasmaType, plasmaProperty, null);
	}
	
	private Column createColumn(Schema schema, Table table, PlasmaType plasmaType, 
			PlasmaProperty plasmaProperty, String derivedPhysicalName) {
		Column column = new Column();
		if (derivedPhysicalName != null)
			column.setName(derivedPhysicalName);
		else
		    column.setName(plasmaProperty.getPhysicalName());
		column.setNullable(plasmaProperty.isNullable());
		if (plasmaProperty.getMaxLength() > 0)
		    column.setSize(plasmaProperty.getMaxLength());
		else
			column.setSize(-1);
		if (plasmaProperty.getType().isDataType()) {
		    DataType sdoType = DataType.valueOf(plasmaProperty.getType().getName());
		    column.setType(sdoType.name());			
		}
		else {
			
			PlasmaProperty oppositePkProp = null;
			
			// FIXME: assumes a single PK !!
			if (!plasmaProperty.getType().isAbstract()) {
				for (Property p : plasmaProperty.getType().getProperties()) {
					PlasmaProperty oppositeProp = (PlasmaProperty)p;
				    if (oppositeProp.isKey(KeyType.primary)) {
				    	if (oppositePkProp != null)
							throw new DDLException("multiple opposite pri-key propertys found for '" 
								+ plasmaProperty.getContainingType().getURI() + "#"
								+ plasmaProperty.getContainingType().getName() + "."
								+ plasmaProperty.getName() + "'");
				    	oppositePkProp = (PlasmaProperty)oppositeProp;
				    }				
				}
			}
			else {
				oppositePkProp = (PlasmaProperty)plasmaType.findProperty(
						KeyType.primary);
				
			}
			
			if (oppositePkProp == null)
				throw new DDLException("could not find opposite pri-key property for '" 
					+ plasmaProperty.getContainingType().getURI() + "#"
					+ plasmaProperty.getContainingType().getName() + "."
					+ plasmaProperty.getName() + "'");
		    DataType sdoType = DataType.valueOf(oppositePkProp.getType().getName());
		    column.setType(sdoType.name());			
		}
		
		return column;
	}
	
	private Table createTable(Schema schema, PlasmaType plasmaType) {
		Table table = new Table();
		String typePhysicalName = null;
		if (plasmaType.getPhysicalName() != null)
			typePhysicalName = plasmaType.getPhysicalName();
		else
			typePhysicalName = this.derivePhysicalName(plasmaType);
		log.debug("creating table: " + typePhysicalName);
		table.setName(typePhysicalName);
		return table;
	}
	
	private Schema createSchema(String name) {
		Schema schema = new Schema();
	    this.schemas.getSchemas().add(schema);
	    schema.setName(name);
	    return schema;
	}
	
	public Schemas getSchemas() {
		return this.schemas;
	}

	/*
	private JDBCType mapType(DataType dataType) {
		switch (dataType) {
		case Boolean: 
			return JDBCType.BOOLEAN;   
		case Byte:        
			return JDBCType.TINYINT;
		case Bytes:      
			return JDBCType.VARBINARY;
		case Character:  
			return JDBCType.CHAR;
		case Decimal:    
			return JDBCType.DECIMAL;
		case Double:     
			return JDBCType.DOUBLE;
		case Float:      
			return JDBCType.FLOAT;
		case Short:      
			return JDBCType.SMALLINT;
		case Int:        
			return JDBCType.INTEGER;
		case Integer:    
		case Long:      
			return JDBCType.BIGINT;
		case String:     
		case Strings:    
		case URI:        
			return JDBCType.VARCHAR;
		case Object:     
			return JDBCType.VARBINARY;
		case Date:       
			return JDBCType.DATE;
		case DateTime:   
			return JDBCType.TIMESTAMP;
		case Time:       
			return JDBCType.TIME;
		case Day:        
		case Duration:   
		case Month:      
		case MonthDay:   
		case Year:       
		case YearMonth:  
		case YearMonthDay:
		default:
			throw new DDLException("unsupported SDO type, "
					+ dataType.toString());
		}		
	}
	*/
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy