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

org.plasma.query.collector.SelectionCollector 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.query.collector;

import java.util.ArrayList;
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 org.plasma.query.InvalidPathPredicateException;
import org.plasma.query.QueryException;
import org.plasma.query.model.AbstractPathElement;
import org.plasma.query.model.AbstractProperty;
import org.plasma.query.model.Function;
import org.plasma.query.model.OrderBy;
import org.plasma.query.model.Path;
import org.plasma.query.model.PathElement;
import org.plasma.query.model.PathNode;
import org.plasma.query.model.Property;
import org.plasma.query.model.Select;
import org.plasma.query.model.Where;
import org.plasma.query.model.WildcardPathElement;
import org.plasma.query.model.WildcardProperty;
import org.plasma.query.visitor.DefaultQueryVisitor;
import org.plasma.query.visitor.QueryVisitor;

import commonj.sdo.Type;

/**
 * Traverses a given {@link Select) clause collecting the specified property
 * names, as well as any path-reference or key properties required for graph
 * structure, into a simple list of logical property name strings mapped to the
 * respective {@link Type} definition.
 * 
 * @see org.plasma.query.model.Select
 * @see commonj.sdo.Type
 */
public class SelectionCollector extends CollectorSupport implements Selection {
	private static Set EMPTY_PROPERTY_SET = new HashSet();
	private static List EMPTY_FUNCTION_LIST = new ArrayList();
	private Select select;
	private Where where;
	private OrderBy orderBy;
	
	// FIXME: what to do with repeated/multiple predicates
	private Map predicateMap;
	private Map> functionMap;
	private Map> propertyMap;
	private Map> singularPropertyMap;
	private Map> inheritedPropertyMap;

	private Map> predicateLevelMap;
	private Map>> functionLevelMap;
	private Map>> propertyLevelMap;
	private Map>> singularPropertyLevelMap;
	private Map>> inheritedPropertyLevelMap;

	private Map> predicateEdgeMap;
	private Map>> propertyEdgeMap;
	private Map>> singularPropertyEdgeMap;
	private Map>> inheritedPropertyEdgeMap;

	public SelectionCollector(Select select, Type rootType) {
		super(rootType);
		this.select = select;
	}

	public SelectionCollector(Select select, Type rootType,
			boolean onlySingularProperties) {
		super(rootType, onlySingularProperties);
		this.select = select;
	}
	
	public SelectionCollector(Select select, Where where, Type rootType) {
		super(rootType);
		this.select = select;
		this.where = where;
	}

	public SelectionCollector(Select select, Where where, Type rootType,
			boolean onlySingularProperties) {
		super(rootType, onlySingularProperties);
		this.select = select;
		this.where = where;
	}
	
	public SelectionCollector(Select select, Where where, OrderBy orderBy, Type rootType) {
		super(rootType);
		this.select = select;
		this.where = where;
		this.orderBy = orderBy;
	}

	public SelectionCollector(Select select, Where where, OrderBy orderBy, Type rootType,
			boolean onlySingularProperties) {
		super(rootType, onlySingularProperties);
		this.select = select;
		this.where = where;
		this.orderBy = orderBy;
	}	
	
	public SelectionCollector(Where where, Type rootType) {
		super(rootType);
		this.where = where;
	}

	public SelectionCollector(Where where, Type rootType,
			boolean onlySingularProperties) {
		super(rootType, onlySingularProperties);
		this.where = where;
	}
	
	private boolean initialized() {
		return this.propertyMap != null;
	}

	private void init() {
		if (!initialized()) {
			this.propertyMap = new HashMap>();
			this.singularPropertyMap = new HashMap>();
			this.inheritedPropertyMap = new HashMap>();
			this.predicateMap = new HashMap();
			this.functionMap = new HashMap>();

			this.propertyLevelMap = new HashMap>>();
			this.singularPropertyLevelMap = new HashMap>>();
			this.inheritedPropertyLevelMap = new HashMap>>();
			this.predicateLevelMap = new HashMap>();
			this.functionLevelMap = new HashMap>>();

			this.propertyEdgeMap = new HashMap>>();
			this.singularPropertyEdgeMap = new HashMap>>();
			this.inheritedPropertyEdgeMap = new HashMap>>();
			this.predicateEdgeMap = new HashMap>();
			
			if (this.select != null) {
				QueryVisitor visitor = new DefaultQueryVisitor() {
					@Override
					public void start(Property property) {
						collect(property);
						super.start(property);
					}
	
					@Override
					public void start(WildcardProperty wildcardProperty) {
						collect(wildcardProperty);
						super.start(wildcardProperty);
					}
				};
				this.select.accept(visitor);
			}
			if (this.where != null) {
				QueryVisitor visitor = new DefaultQueryVisitor() {
					@Override
					public void start(Property property) {
						collect(property);
						super.start(property);
					}
	
					@Override
					public void start(WildcardProperty wildcardProperty) {
						collect(wildcardProperty);
						super.start(wildcardProperty);
					}
				};
				this.where.accept(visitor);
			}
			if (this.orderBy != null) {
				QueryVisitor visitor = new DefaultQueryVisitor() {
					@Override
					public void start(Property property) {
						collect(property);
						super.start(property);
					}
	
					@Override
					public void start(WildcardProperty wildcardProperty) {
						collect(wildcardProperty);
						super.start(wildcardProperty);
					}
				};
				this.orderBy.accept(visitor);
			}
		}
	}
	
	@Deprecated
	public Map getPredicateMap() {
		if (!initialized())
		    init();
		return predicateMap;
	}

	/**
	 * (non-Javadoc)
	 */
	public boolean hasPredicates() {
		if (!initialized())
		    init();
		if (predicateMap == null)
			return false;
		return predicateMap.size() > 0;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.plasma.query.collector.PropertySelection#getPredicate(commonj.sdo
	 * .Property)
	 */
	@Override
	public Where getPredicate(commonj.sdo.Property property) {
		if (!initialized())
			init();
		if (this.predicateMap != null)
			return this.predicateMap.get(property);
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.plasma.query.collector.PropertySelection#getSingularProperties(commonj
	 * .sdo.Type)
	 */
	@Override
	public Set getSingularProperties(Type type) {
		if (!initialized())
			init();
		Set result = this.singularPropertyMap.get(type);
		if (result != null)
			return result;
		return EMPTY_PROPERTY_SET;
	}

	/*
	 * (non-Javadoc)
	 * 
	 */
	@Override
	public Set getProperties(Type type) {
		if (!initialized())
			init();
		Set result = propertyMap.get(type);
		if (result != null)
			return result;
		return EMPTY_PROPERTY_SET;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.plasma.query.collector.Selection#getInheritedProperties(Type type)
	 */
	@Override
	public Set getInheritedProperties(Type type) {
		if (!initialized())
			init();
		Set result = inheritedPropertyMap.get(type);
		if (result != null)
			return result;
		return EMPTY_PROPERTY_SET;
	}
	
	@Override
	public Set getInheritedProperties(Type type,
			commonj.sdo.Property sourceProperty) {
		if (!initialized())
			init();
		Map> edgeMap = this.inheritedPropertyEdgeMap.get(type);
		if (edgeMap != null) {
		    Set set = edgeMap.get(sourceProperty);
		    if (set != null)
		    	return set;
		}				 
		return EMPTY_PROPERTY_SET;
	}
	
	/*
	 * (non-Javadoc)
	 * @see
	 * org.plasma.query.collector.Selection#getInheritedProperties(Type type, int level)
	 */
	@Override
	public Set getInheritedProperties(Type type, int level) {
		if (!initialized())
			init();
		Map> levelMap = this.inheritedPropertyLevelMap.get(type);
		if (levelMap != null) {
		    Set set = levelMap.get(level);
		    if (set != null)
		    	return set;
		}				 
		return EMPTY_PROPERTY_SET;
	}

	@Override
	public Set getInheritedProperties(Type type,
			commonj.sdo.Property sourceProperty, int level) {
		Set result = new HashSet();
		Set levelProps = getInheritedProperties(type, level);
		Set edgeProps = getInheritedProperties(type, sourceProperty);		
		for (commonj.sdo.Property p : levelProps) {
			if (edgeProps.contains(p))
				result.add(p);
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * @see
	 * org.plasma.query.collector.Selection#getTypes()
	 */
	@Override
	public List getTypes() {
		if (!initialized())
			init();
		List result = new ArrayList();
		result.addAll(this.propertyMap.keySet());
		result.addAll(this.inheritedPropertyMap.keySet());
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.plasma.query.collector.Selection#hasType(commonj.sdo.Type)
	 */
	@Override
	public boolean hasType(Type type) {
		if (!initialized())
			init();
		return this.propertyMap.get(type) != null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.plasma.query.collector.PropertySelection#getInheritedTypes(commonj
	 * .sdo.Type)
	 */
	@Override
	public List getInheritedTypes() {
		if (!initialized())
			init();
		List result = new ArrayList();
		result.addAll(this.inheritedPropertyMap.keySet());
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.plasma.query.collector.PropertySelection#hasInheritedType(commonj
	 * .sdo.Type)
	 */
	@Override
	public boolean hasInheritedType(Type type) {
		if (!initialized())
			init();
		return this.inheritedPropertyMap.get(type) != null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.plasma.query.collector.PropertySelection#hasProperty(commonj.sdo.
	 * Type, commonj.sdo.Property)
	 */
	@Override
	public boolean hasProperty(Type type, commonj.sdo.Property property) {
		if (!initialized())
			init();
		Set props = this.propertyMap.get(type);
		if (props != null && props.size() > 0) {
			if (props.contains(property))
				return true;
		}
		return false;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.plasma.query.collector.PropertySelection#addProperty(commonj.sdo.
	 * Type, commonj.sdo.Property)
	 */
	@Override
	public List addProperty(Type rootType, String path) {
		List result = new ArrayList();
		Type contextType = rootType;
		StringBuilder buf = new StringBuilder();
		String[] tokens = path.split("/");
		for (int i = 0; i < tokens.length; i++) {
			if (i > 0)
				buf.append("/");
			String token = tokens[i];
			int right = token.indexOf("[");
			if (right >= 0) // remove predicate - were just after the path
				token = token.substring(0, right);
			int attr = token.indexOf("@");
			if (attr == 0)
				token = token.substring(1);
			commonj.sdo.Property prop = contextType.getProperty(token);
			this.addProperty(contextType, prop, this.propertyMap);
			this.addInheritedProperty(contextType, prop,
					this.inheritedPropertyMap);
			if (!prop.getType().isDataType()) {
				contextType = prop.getType(); // traverse
				result.add(contextType);
			}
			buf.append(prop.getName());
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.plasma.query.collector.PropertySelection#hasInheritedProperty(commonj
	 * .sdo.Type, commonj.sdo.Property)
	 */
	@Override
	public boolean hasInheritedProperty(Type type, commonj.sdo.Property property) {
		if (!initialized())
			init();
		Set props = this.inheritedPropertyMap.get(type);
		if (props != null && props.size() > 0) {
			if (props.contains(property))
				return true;
		}
		return false;
	}


	@Override
	public Set getProperties(Type type, int level) {
		if (!initialized())
			init();
		Map> levelMap = this.propertyLevelMap.get(type);
		if (levelMap != null) {
		    Set set = levelMap.get(level);
		    if (set != null)
		    	return set;
		}				 
		return EMPTY_PROPERTY_SET;
	}

	@Override
	public Set getProperties(Type type,
			commonj.sdo.Property sourceProperty) {
		if (!initialized())
			init();
		Map> edgeMap = this.propertyEdgeMap.get(type);
		if (edgeMap != null) {
		    Set set = edgeMap.get(sourceProperty);
		    if (set != null)
		    	return set;
		}				 
		return EMPTY_PROPERTY_SET;
	}

	@Override
	public Set getProperties(Type type,
			commonj.sdo.Property sourceProperty, int level) {
		Set result = new HashSet();
		result.addAll(getProperties(type, level));
		result.addAll(getProperties(type, sourceProperty));
		return result;
	}

	@Override
	public Where getPredicate(commonj.sdo.Property property,
			commonj.sdo.Property sourceProperty) {
		if (!initialized())
			init();
		Map edgeMap = this.predicateEdgeMap.get(property);
		if (edgeMap != null) {
			return edgeMap.get(sourceProperty);
		}
		return null;
	}

	@Override
	public Where getPredicate(commonj.sdo.Property property, int level) {
		if (!initialized())
			init();
		Map levelMap = this.predicateLevelMap.get(property);
		if (levelMap != null) {
			return levelMap.get(level);
		}
		return null;
	}
	
	@Override
	public List getFunctions(commonj.sdo.Property property) {
		if (!initialized())
			init();
		List list = this.functionMap.get(property);
		if (list != null) {
			return list;
		}
		return EMPTY_FUNCTION_LIST;
	}

	@Override
	public List getFunctions(commonj.sdo.Property property, int level) {
		if (!initialized())
			init();
		Map> levelMap = this.functionLevelMap.get(property);
		if (levelMap != null) {
			List list = levelMap.get(level);
			if (list != null)
				return list;
		}
		return EMPTY_FUNCTION_LIST;
	}
	
	private void collect(AbstractProperty abstractProperty) {
		Path path = null;
		if (abstractProperty instanceof Property) {
			path = ((Property) abstractProperty).getPath();
		} else if (abstractProperty instanceof WildcardProperty) {
			path = ((WildcardProperty) abstractProperty).getPath();
		} else
			throw new IllegalArgumentException("unknown property class, "
					+ abstractProperty.getClass().getName());
		if (path == null) {
			commonj.sdo.Property[] props = this.findProperties(rootType,
					abstractProperty);
			this.mapProperties(this.rootType, props, this.propertyMap);
			this.mapInheritedProperties(this.rootType, props,
					this.inheritedPropertyMap);
			Integer level = Integer.valueOf(0);
			this.mapProperties(this.rootType, level, props,
					this.propertyLevelMap);
			this.mapInheritedProperties(this.rootType, level, props,
					this.inheritedPropertyLevelMap);
			if (abstractProperty instanceof Property) {
				Property property = (Property)abstractProperty;
				commonj.sdo.Property prop = this.rootType.getProperty(property.getName());
				List functions = property.getFunctions();
				if (functions != null && functions.size() > 0) {
					this.mapFunctions(prop, functions, this.functionMap);
					this.mapFunctions(prop, level, functions,
							this.functionLevelMap);
				}
			}
			// no source property so don't add source property mappings
		} else {
			if (!this.isOnlySingularProperties()) {
				collect(path, rootType, path.getPathNodes().get(0), 0,
						abstractProperty, null, 0);
			} else {
				if (this.isSingularPath(path, rootType, abstractProperty))
					collect(path, rootType, path.getPathNodes().get(0), 0,
							abstractProperty, null, 0);
			}
		}
	}

	/**
	 * Recursively collects properties, predicates and functions from the given path. 
	 * 
	 * @param path
	 *            the path
	 * @param currType
	 *            the current type
	 * @param currPathElement
	 *            the current path element/node
	 * @param curPathElementIndex
	 *            the current path element/node index
	 * @param abstractProperty
	 *            the property
	 * @param map
	 *            the property map
	 */
	private void collect(Path path, Type currType, PathNode currPathode,
			int curPathElementIndex, AbstractProperty abstractProperty,
			commonj.sdo.Property edge, int level) {

		AbstractPathElement currPathElement = currPathode.getPathElement();
		if (currPathElement instanceof PathElement) {
			PathElement pathElement = (PathElement) currPathElement;
			commonj.sdo.Property prop = currType.getProperty(pathElement
					.getValue());

			if (prop.getType().isDataType())
				if (abstractProperty instanceof Property)
					throw new QueryException("traversal path for property '"
							+ ((Property) abstractProperty).getName()
							+ "' from root '" + rootType.getName()
							+ "' contains a non-reference property '"
							+ prop.getName() + "'");
				else
					throw new QueryException(
							"traversal path for wildcard property "
									+ "' from root '" + rootType.getName()
									+ "' contains a non-reference property '"
									+ prop.getName() + "'");


			if (prop.isMany() && this.isOnlySingularProperties())
				return;
			
			this.addProperty(currType, prop, this.propertyMap);
			this.addInheritedProperty(currType, prop, this.inheritedPropertyMap);
			
			this.addProperty(currType, level, prop, this.propertyLevelMap);
			this.addInheritedProperty(currType, level, prop, this.inheritedPropertyLevelMap);

			if (currPathode.getWhere() != null) {
				this.predicateMap.put(prop, currPathode.getWhere());
				this.addPredicate(prop, level, currPathode.getWhere(), this.predicateLevelMap);
			}

			Type nextType = prop.getType(); // traverse

			if (path.getPathNodes().size() > curPathElementIndex + 1) { // more
																		// nodes
				if (edge != null) {
					this.addProperty(currType, edge, prop, this.propertyEdgeMap);
					this.addInheritedProperty(currType, edge, prop, this.inheritedPropertyEdgeMap);
					if (currPathode.getWhere() != null)
					    this.addPredicate(prop, edge, currPathode.getWhere(), this.predicateEdgeMap);
				}

				int nextPathElementIndex = curPathElementIndex + 1;
				PathNode nextPathNode = path.getPathNodes().get(
						nextPathElementIndex);
				collect(path, nextType, nextPathNode, nextPathElementIndex,
						abstractProperty, prop, level + 1);
			} else { // reached the path endpoint
				commonj.sdo.Property[] props = this.findProperties(nextType,
						abstractProperty);
				this.mapProperties(nextType, props, this.propertyMap);
				this.mapInheritedProperties(nextType, props,
						this.inheritedPropertyMap);
				this.mapProperties(nextType, level+1, props,
						this.propertyLevelMap);
				this.mapInheritedProperties(nextType, level+1, props,
						this.inheritedPropertyLevelMap);
				// current property is the edge
				this.mapProperties(nextType, prop, props,
						this.propertyEdgeMap);
				this.mapInheritedProperties(nextType, prop, props,
						this.inheritedPropertyEdgeMap);
				if (abstractProperty instanceof Property) {
					Property property = (Property)abstractProperty;
					List functions = property.getFunctions();
					if (functions != null && functions.size() > 0) {
						this.mapFunctions(prop, functions, this.functionMap);
						this.mapFunctions(prop, level, functions,
								this.functionLevelMap);
					}	
				}
			}
		} else if (currPathElement instanceof WildcardPathElement) {
			List properties = null;
			if (this.onlyDeclaredProperties)
				properties = currType.getDeclaredProperties();
			else
				properties = currType.getProperties();

			if (currPathode.getWhere() != null)
				throw new InvalidPathPredicateException(
						"path predicate found on wildcard path element");

			for (commonj.sdo.Property prop : properties) {
				if (prop.getType().isDataType())
					continue;
				if (prop.isMany() && this.isOnlySingularProperties())
					return;

				this.addProperty(currType, prop, this.propertyMap);
				this.addInheritedProperty(currType, prop,
						this.inheritedPropertyMap);
				if (edge != null) {
					this.addProperty(currType, edge, prop,
							this.propertyEdgeMap);
					this.addInheritedProperty(currType, edge, prop,
							this.inheritedPropertyEdgeMap);
				}
				
				Type nextType = prop.getType();

				if (path.getPathNodes().size() > curPathElementIndex + 1) { // more path nodes
					this.addProperty(currType, level, prop,
							this.propertyLevelMap);
					this.addInheritedProperty(currType, level, prop,
							this.inheritedPropertyLevelMap);
					int nextPathElementIndex = curPathElementIndex + 1;
					PathNode nextPathNode = path.getPathNodes().get(
							nextPathElementIndex);
					collect(path, nextType, nextPathNode, nextPathElementIndex,
							abstractProperty, prop, level + 1);
				} else {
					this.addProperty(currType, level+1, prop,
							this.propertyLevelMap);
					this.addInheritedProperty(currType, level+1, prop,
							this.inheritedPropertyLevelMap);
					commonj.sdo.Property[] props = this.findProperties(
							nextType, abstractProperty);

					this.mapProperties(nextType, props, this.propertyMap);
					this.mapInheritedProperties(nextType, props,
							this.inheritedPropertyMap);					
					this.mapProperties(nextType, level+1, props,
							this.propertyLevelMap);
					this.mapInheritedProperties(nextType, level+1, props,
							this.inheritedPropertyLevelMap);
					// cur property is the edge
					this.mapProperties(nextType, prop, props,
							this.propertyEdgeMap);
					this.mapInheritedProperties(nextType, prop, props,
							this.inheritedPropertyEdgeMap);

					if (abstractProperty instanceof Property) {
						Property property = (Property)abstractProperty;
						List functions = property.getFunctions();
						if (functions != null && functions.size() > 0) {
							this.mapFunctions(prop, functions, this.functionMap);
							this.mapFunctions(prop, level, functions,
									this.functionLevelMap);
						}	
					}
				}
			}
		} else
			throw new IllegalArgumentException("unknown path element class, "
					+ currPathElement.getClass().getName());
	}

	public String dumpProperties() {
		StringBuilder buf = new StringBuilder();
		Iterator typeIter = this.propertyMap.keySet().iterator();
		while (typeIter.hasNext()) {
			Type type = typeIter.next();
			buf.append("\n" + type.getURI() + "#" + type.getName());
			Set props = this.propertyMap.get(type);
			for (commonj.sdo.Property prop : props) {
				buf.append("\n\t" + prop.getName());
			}
		}
		return buf.toString();
	}

	public String dumpInheritedProperties() {
		StringBuilder buf = new StringBuilder();
		Iterator typeIter = this.inheritedPropertyMap.keySet().iterator();
		while (typeIter.hasNext()) {
			Type type = typeIter.next();
			buf.append("\n" + type.getURI() + "#" + type.getName());
			Set props = this.inheritedPropertyMap
					.get(type);
			for (commonj.sdo.Property prop : props) {
				buf.append("\n\t" + prop.getName());
			}
		}
		return buf.toString();
	}


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy