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

org.plasma.provisioning.adapter.ModelAdapter 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.provisioning.adapter;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
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.metamodel.Alias;
import org.plasma.metamodel.Class;
import org.plasma.metamodel.ClassRef;
import org.plasma.metamodel.Enumeration;
import org.plasma.metamodel.EnumerationRef;
import org.plasma.metamodel.Model;
import org.plasma.metamodel.Package;
import org.plasma.metamodel.Property;
import org.plasma.provisioning.PropertyNameCollisionException;
import org.plasma.provisioning.ProvisioningException;
import org.plasma.provisioning.TypeNameCollisionException;

public class ModelAdapter implements ProvisioningModel {
    private static Log log = LogFactory.getLog(
			   ModelAdapter.class); 

    private Model model;
    private Map typeMap = new HashMap();
    private List leafPackages = new ArrayList();
    private List allPackages = new ArrayList();
    private Map packageTypeMap = new HashMap();
    
    @SuppressWarnings("unused")
	private ModelAdapter() {}
    
    public ModelAdapter(Model model) {
    	this.model = model;
    	construct();
    }
    
    /* (non-Javadoc)
	 * @see org.plasma.provisioning.adapter.MetamodelAdapter#getModel()
	 */
    @Override
	public Model getModel() {
		return model;
	}
    
	@Override
	public List getPackages() {
		return Collections.unmodifiableList(this.allPackages);
	}
    
    
    /* (non-Javadoc)
	 * @see org.plasma.provisioning.adapter.MetamodelAdapter#getLeafPackages()
	 */
    @Override
	public List getLeafPackages() {
    	return Collections.unmodifiableList(this.leafPackages);
    }
    
	@Override
	public Package getPackage(TypeAdapter type) {
		return this.packageTypeMap.get(type);
	}
    
    /* (non-Javadoc)
	 * @see org.plasma.provisioning.adapter.MetamodelAdapter#getTypes()
	 */
    @Override
	public Collection getTypes() {
    	return typeMap.values();
    }
    
    /* (non-Javadoc)
	 * @see org.plasma.provisioning.adapter.MetamodelAdapter#getTypesArray()
	 */
    @Override
	public TypeAdapter[] getTypesArray() {
    	TypeAdapter[] result = new TypeAdapter[typeMap.size()];
    	typeMap.values().toArray(result);
    	return result;
    }
    
    /* (non-Javadoc)
	 * @see org.plasma.provisioning.adapter.MetamodelAdapter#getTypesArray()
	 */
	@Override
	public Map getTypeMap() {
		return Collections.unmodifiableMap(typeMap);
	}

	/* (non-Javadoc)
	 * @see org.plasma.provisioning.adapter.MetamodelAdapter#findType(java.lang.String)
	 */
	@Override
	public TypeAdapter findType(String key) {
    	TypeAdapter result = typeMap.get(key);
    	return result;
    }
	
	private void findPackages(Package parent, List packages) {
		packages.add(parent);
    	for (Package childPkg : parent.getPackages()) {
    		findPackages(childPkg, packages);
    	}
	}
	
    private void construct() {
		if (log.isDebugEnabled())
			log.debug("constructing...");
		
		findPackages(this.model, this.allPackages);
		
    	for (Package pkg : this.allPackages)
    		if (pkg.getPackages().size() == 0)
    			this.leafPackages.add(pkg);		
		
    	for (Package pkg : this.allPackages)
    		mapEnumerations(pkg);
    	
    	for (Package pkg : this.allPackages)
    		mapClasses(pkg);
    	
    	for (TypeAdapter adapter : typeMap.values()) {
    		if (adapter.getType() instanceof Class) {    		
    			if (log.isDebugEnabled())
    				log.debug("constructing class: " + adapter.getKey());
    		    construct(adapter, null);
    		}
    	} 
    	
    	for (TypeAdapter adapter : typeMap.values()) {
    		if (adapter.getType() instanceof Class) { 
    	    	for (ClassRef baseClassRef : ((Class)adapter.getType()).getSuperClasses()) {
    	    		String key = baseClassRef.getUri() + "#" + baseClassRef.getName();
    	    		TypeAdapter baseAdapter = typeMap.get(key);
    	    		if (baseAdapter == null)
    	    			throw new IllegalStateException("no mapping found for base type: " + key); 
    						
        			if (log.isDebugEnabled())
        				log.debug("construct deep: " + adapter.getKey());
    				constructDeep(adapter, baseAdapter);
    			}
    		}
    	}    	
    }
    
    private void mapEnumerations(Package pkg) {
		if (log.isDebugEnabled())
			log.debug("mapping enumerations for package " + pkg.getUri() + " (" + pkg.getName() + ")" );
    	for (Enumeration enm : pkg.getEnumerations()) {
    		String key = enm.getUri() + "#" + enm.getName();
    		if (log.isDebugEnabled())
    			log.debug("mapping enumeration: " + key);
    		if (typeMap.get(key) != null)
    			throw new TypeNameCollisionException(
    				"detected multiple types named '"+enm.getName()+"' under the same URI '"
    				+ enm.getUri() + "'");
    		TypeAdapter adapter = new TypeAdapter(enm);
    		this.typeMap.put(key, adapter);
    		this.packageTypeMap.put(adapter, pkg);
    	}
    }   
    
    private void mapClasses(Package pkg) {
		for (Class cls : pkg.getClazzs()) {
			String key = cls.getUri() + "#" + cls.getName();
			if (log.isDebugEnabled())
				log.debug("mapping class: " + key);
			if (typeMap.get(key) != null)
				throw new TypeNameCollisionException(
					"detected multiple types named '"+cls.getName()+"' under the same URI '"
					+ cls.getUri() + "'");
			
			TypeAdapter adapter = new TypeAdapter(cls);
    		this.typeMap.put(key, adapter);
    		this.packageTypeMap.put(adapter, pkg);
			if (log.isDebugEnabled())
				log.debug("map: " + adapter.getKey());
		}
    }

    private void construct(TypeAdapter adapter, TypeAdapter source)
    {    	
    	for (Property prop: ((Class)adapter.getType()).getProperties()) {
		    if (adapter.getDeclaredProperty(prop.getName()) != null)
		    	throw new PropertyNameCollisionException(
	    			"detected multiple properties with the same logical name '"
		    		+ prop.getName() + "' defined for class '"
	    			+ adapter.getKey() + "' the set of logical names for a class "
	    			+ "must be unique");
		    adapter.putDeclaredProperty(prop.getName(), prop);
		    adapter.putProperty(prop.getName(), prop); // note: all property collection not declared only
		    if (prop.getAlias() != null) {
		    	Alias alias = prop.getAlias();
			    if (alias.getPhysicalName() != null && alias.getPhysicalName().trim().length() > 0) {
				    String physicalName = alias.getPhysicalName().trim();
			    	if (adapter.getAliasedProperty(physicalName) != null)
				    	throw new PropertyNameCollisionException(
			    			"detected multiple properties with the same physical name '"
				    		+ alias + "' defined for class '"
			    			+ adapter.getKey() + "' the set of physical names for a class "
			    			+ "must be unique");
				    adapter.putAliasedProperty(physicalName, prop);
			    }
			    if (alias.getLocalName() != null && alias.getLocalName().trim().length() > 0) {
				    String localName = prop.getAlias().getLocalName().trim();
			    	if (adapter.getAliasedProperty(localName) != null)
				    	throw new PropertyNameCollisionException(
			    			"detected multiple properties with the same local name '"
				    		+ alias + "' defined for class '"
			    			+ adapter.getKey() + "' the set of local names for a class "
			    			+ "must be unique");
				    adapter.putAliasedProperty(localName, prop);
			    }
		    }
		}
    }

    private void constructDeep(TypeAdapter adapter, TypeAdapter baseAdapter)
    {
    	// copy base properties into subclass
    	for (Property prop: ((Class)baseAdapter.getType()).getProperties()) {
		    if (adapter.getProperty(prop.getName()) != null)
		    	throw new PropertyNameCollisionException(
	    			"detected multiple properties with the same logical name '"
		    		+ prop.getName() + "' defined for class '"
	    			+ adapter.getKey() + "' as well as its superclass '"
	    			+ baseAdapter.getKey() + "' - the set of logical names for a class and "
	    			+ "superclasses must be unique");
		    validate(baseAdapter, adapter, prop);
		    adapter.putProperty(prop.getName(), prop); // note: all property collection not declared only
		    if (prop.getAlias() != null && prop.getAlias().getPhysicalName() != null && prop.getAlias().getPhysicalName().trim().length() > 0) {
			    String alias = prop.getAlias().getPhysicalName().trim();
		    	if (adapter.getAliasedProperty(alias) != null)
			    	throw new PropertyNameCollisionException(
			    			"detected multiple properties with the same physical name '"
				    		+ alias + "' defined for class '"
			    			+ adapter.getKey() + "' as well as its superclass '"
			    			+ baseAdapter.getKey() + "' - the set of logical names for a class and "
			    			+ "superclasses must be unique");
		    	adapter.putAliasedProperty(alias, prop);
		    }
		}

    	for (ClassRef baseClassRef : ((Class)baseAdapter.getType()).getSuperClasses()) {
    		String key2 = baseClassRef.getUri() + "#" + baseClassRef.getName();
    		TypeAdapter baseTypeAdapter = typeMap.get(key2);
    		if (baseTypeAdapter == null)
    			throw new IllegalStateException("no mapping found for base type: " + key2); 
					
			constructDeep(adapter, baseTypeAdapter);
		}
    }
    
    private void validate(TypeAdapter adapter, TypeAdapter source, Property prop)
    {
	    if (prop.getType() instanceof ClassRef) {
	    	ClassRef ref = (ClassRef)prop.getType();
	    	String refkey = ref.getUri() + "#" + ref.getName();
    		if (typeMap.get(refkey) == null)
		    	throw new ProvisioningException(
		    			"invalid type reference detected for property '"
			    		+ adapter.getKey() + "." + prop.getName() + "' no class or enumeration '"
		    			+ refkey + "' is defined");
    		if (prop.getOpposite() != null) {
    			Class oppositeClass = (Class)typeMap.get(refkey).getType();
    			Property oppositeProperty = findPropertyByName(oppositeClass, prop.getOpposite());
    			if (oppositeProperty == null)
			    	throw new ProvisioningException(
			    			"invalid opposite reference detected for property '"
				    		+ adapter.getKey() + "." + prop.getName() + "' no opposite property '"
				    		+ prop.getOpposite() + "' is defined for class '"
			    			+ refkey + "'");
    		}
	    }
	    if (prop.getType() instanceof EnumerationRef) {
	    	EnumerationRef ref = (EnumerationRef)prop.getType();
	    	String refkey = ref.getUri() + "#" + ref.getName();
    		if (typeMap.get(refkey) == null)
		    	throw new ProvisioningException(
		    			"invalid type reference detected for property '"
			    		+ prop.getName() + "' defined for class '"
		    			+ adapter.getKey() + "'");
	    }
    }    
    
    private Property findPropertyByName(Class clss, String name) {
        for (Property prop : clss.getProperties()) {
        	if (name.equals(prop.getName()))
        		return prop;
        }
        return null;
    }



}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy