/* * The contents of this file are subject to the Open Software License * Version 3.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.opensource.org/licenses/osl-3.0.txt * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. */ package org.mulgara.resolver.spi; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import org.mulgara.query.Constraint; import org.mulgara.query.ConstraintConjunction; import org.mulgara.query.ConstraintDifference; import org.mulgara.query.ConstraintDisjunction; import org.mulgara.query.ConstraintExpression; import org.mulgara.query.ConstraintFilter; import org.mulgara.query.ConstraintIn; import org.mulgara.query.ConstraintOperation; import org.mulgara.query.ConstraintOptionalJoin; /** * This provides some common processing for symbolic-transformers. * * @created Dec 2, 2008 * @author Paula Gearon * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a> * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a> */ public abstract class AbstractSymbolicTransformer implements SymbolicTransformation { private static final Logger logger = Logger.getLogger(AbstractSymbolicTransformer.class); public void transform(SymbolicTransformationContext context, MutableLocalQuery mutableLocalQuery) throws SymbolicTransformationException { if (logger.isTraceEnabled()) logger.trace("Transforming query: " + mutableLocalQuery.getConstraintExpression()); ConstraintExpression expr = mutableLocalQuery.getConstraintExpression(); ConstraintExpression trans = transformExpression(context, expr); if (logger.isTraceEnabled()) logger.trace("Transform result: " + (expr != trans ? trans : "-no-change-")); if (expr != trans) { mutableLocalQuery.setConstraintExpression(trans); } } /** * Transform the given constraint-expression. This is a dispatcher, invoking one of the other * transformXYZ methods as applicable or returning the given expr if none are. * * @param context the current transformation context * @param expr the constraint expression to transform * @return a new expression is something was changed, or <var>expr</var> if nothing was changed. * @throws SymbolicTransformationException If there is an error applying the transform */ public ConstraintExpression transformExpression(SymbolicTransformationContext context, ConstraintExpression expr) throws SymbolicTransformationException { // explicitly handle all the recursive types if (expr instanceof ConstraintFilter) return transformFilter(context, (ConstraintFilter)expr); if (expr instanceof ConstraintIn) return transformIn(context, (ConstraintIn)expr); if (expr instanceof ConstraintOperation) return transformOperation(context, (ConstraintOperation)expr); // do the actual work of this transformer if (expr instanceof Constraint) return transformConstraint(context, (Constraint)expr); // By default we do not recognise the constraint type, so pass it unchanged. return expr; } /** * Transform the filtered constraint. This invokes {@link #transformExpression} on the inner constraint. * * @param context the current transformation context * @param filter the constraint filter to transform * @return a new expression is something was changed, or <var>filter</var> if nothing was changed. * @throws SymbolicTransformationException If there is an error applying the transform */ protected ConstraintExpression transformFilter(SymbolicTransformationContext context, ConstraintFilter filter) throws SymbolicTransformationException { ConstraintExpression inner = filter.getUnfilteredConstraint(); ConstraintExpression tx = transformExpression(context, inner); return (tx == inner) ? filter : new ConstraintFilter(tx, filter.getFilter()); } /** * Transform the in constraint. This invokes {@link #transformExpression} on the inner constraint. * * @param context the current transformation context * @param in the in-constraint to transform * @return a new expression is something was changed, or <var>in</var> if nothing was changed. * @throws SymbolicTransformationException If there is an error applying the transform */ protected ConstraintExpression transformIn(SymbolicTransformationContext context, ConstraintIn in) throws SymbolicTransformationException { ConstraintExpression inner = in.getConstraintParam(); ConstraintExpression tx = transformExpression(context, inner); return (tx == inner) ? in : new ConstraintIn(tx, in.getGraph()); } /** * Transform the constraint-operation. This invokes {@link #transformExpression} on all the inner * constraints. * * @param context the current transformation context * @param oper the constraint-operation to transform * @return a new expression is something was changed, or <var>oper</var> if nothing was changed. * @throws SymbolicTransformationException If there is an error applying the transform */ protected ConstraintExpression transformOperation(SymbolicTransformationContext context, ConstraintOperation oper) throws SymbolicTransformationException { List<ConstraintExpression> ops = oper.getElements(); List<ConstraintExpression> newOps = new ArrayList<ConstraintExpression>(ops.size()); boolean changed = false; for (ConstraintExpression op: ops) { ConstraintExpression tx = transformExpression(context, op); newOps.add(tx); if (tx != op) changed = true; } if (changed) { OpType operationType = OpType.getType(oper); if (operationType == null) throw new SymbolicTransformationException("Encountered an unknown operation type: " + oper.getClass()); return operationType.newOp(newOps); } return oper; } /** * Transform the given expression. The main work of this class is usually performed in this * method. * * @param context the current transformation context * @param c the constraint to transform. * @return the original constraint, or a new constraint if something was changed. * @throws SymbolicTransformationException If there is an error applying the transform */ protected abstract ConstraintExpression transformConstraint(SymbolicTransformationContext context, Constraint c) throws SymbolicTransformationException; /** * This enum enumerates the ConstraintOperation types. It has been built to deal with * the fact that constructors for the various types cannot be passed as a lambda. * It also provides a map for the enumerated types to their enumerations, making it * easy for an operation to get to an appropriate constructor. */ protected static enum OpType { difference { public ConstraintOperation newOp(List<ConstraintExpression> ops) { return new ConstraintDifference(ops.get(0), ops.get(1)); } }, optional { public ConstraintOperation newOp(List<ConstraintExpression> ops) { return new ConstraintOptionalJoin(ops.get(0), ops.get(1)); } }, conjunction { public ConstraintOperation newOp(List<ConstraintExpression> ops) { return new ConstraintConjunction(ops); } }, disjunction { public ConstraintOperation newOp(List<ConstraintExpression> ops) { return new ConstraintDisjunction(ops); } }; public abstract ConstraintOperation newOp(List<ConstraintExpression> ops); private static Map<Class<? extends ConstraintOperation>, OpType> opMap = new HashMap<Class<? extends ConstraintOperation>, OpType>(); public static OpType getType(ConstraintOperation op) { return opMap.get(op.getClass()); } static { opMap.put(ConstraintDifference.class, difference); opMap.put(ConstraintOptionalJoin.class, optional); opMap.put(ConstraintConjunction.class, conjunction); opMap.put(ConstraintDisjunction.class, disjunction); } } }