/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (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.mozilla.org/MPL/
*
* 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.
*
* The Original Code is the Kowari Metadata Store.
*
* The Initial Developer of the Original Code is Plugged In Software Pty
* Ltd (http://www.pisoftware.com, mailto:info@pisoftware.com). Portions
* created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
* Northrop Grumman Corporation. All Rights Reserved.
*
* This file is an original work and contains no Original Code. It was
* developed by Netymon Pty Ltd under contract to the Australian
* Commonwealth Government, Defense Science and Technology Organisation
* under contract #4500507038 and is contributed back to the Kowari/Mulgara
* Project as per clauses 4.1.3 and 4.1.4 of the above contract.
*
* Contributor(s): N/A.
*
* Copyright:
* The copyright on this file is held by:
* The Australian Commonwealth Government
* Department of Defense
* Developed by Netymon Pty Ltd
* Copyright (C) 2006
* The Australian Commonwealth Government
* Department of Defense
*
* [NOTE: The text of this Exhibit A may differ slightly from the text
* of the notices in the Source Code files of the Original Code. You
* should use the text of this Exhibit A rather than the text found in the
* Original Code Source Code for Your Modifications.]
*
*/
package org.mulgara.resolver.spi;
import org.apache.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
import java.util.Arrays;
import java.net.URI;
import org.jrdf.graph.URIReference;
import org.mulgara.query.Constraint;
import org.mulgara.query.ConstraintElement;
import org.mulgara.query.Variable;
import org.mulgara.query.ConstraintExpression;
import org.mulgara.query.ConstraintConjunction;
import org.mulgara.query.ConstraintDisjunction;
import org.mulgara.query.QueryException;
/**
* A transformer that works on the basis of combining multiple conjoined constraints
* into a single compound constraint.
*
* @modified $Date: 2005/10/30 19:21:17 $ by $Author: prototypo $
* @maintenanceAuthor $Author: prototypo $
* @copyright ©2006 <a href="http://www.defence.gov.au/">
* Australian Commonwealth Government, Department of Defence</a>
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
public abstract class ConjunctiveTransformer extends AbstractSymbolicTransformer {
/** Logger */
@SuppressWarnings("unused")
private static final Logger logger = Logger.getLogger(ConjunctiveTransformer.class.getName());
protected URI modelTypeURI;
public ConjunctiveTransformer(URI modelTypeURI) {
this.modelTypeURI = modelTypeURI;
}
public abstract ConstraintExpression constructConstraintExpression(ConstraintElement model, Map<ConstraintElement,Map<ConstraintElement,List<ConstraintElement>>> byVarSubject, Map<ConstraintElement,Map<ConstraintElement,List<ConstraintElement>>> byConstSubject) throws SymbolicTransformationException;
@Override
public ConstraintExpression transformExpression(SymbolicTransformationContext context, ConstraintExpression expr) throws SymbolicTransformationException {
// This is the main case.
if (expr instanceof ConstraintConjunction) {
return transformConj(context, (ConstraintConjunction)expr);
}
// A single constraint could still be transformed as a singleton conjunction.
// Therefore pack in conjunction, attempt transform, and check to see if it was.
if (expr instanceof Constraint) {
ConstraintConjunction conj = new ConstraintConjunction(Arrays.asList(new ConstraintExpression[] { expr }));
ConstraintConjunction trans = transformConj(context, conj);
if (conj == trans) {
return expr;
} else {
return trans;
}
}
// all else go through the default handling
return super.transformExpression(context, expr);
}
@Override
protected ConstraintExpression transformConstraint(SymbolicTransformationContext context,
Constraint c)
throws SymbolicTransformationException {
return c;
}
public ConstraintConjunction transformConj(SymbolicTransformationContext context, ConstraintConjunction cc) throws SymbolicTransformationException {
ConjAccumulator acc = transformConj(context, cc, new ConjAccumulator(context));
if (!acc.isTransformed()) {
return cc;
}
List<ConstraintExpression> args = new ArrayList<ConstraintExpression>();
args.addAll(acc.getResidualArgs());
ArgMap varSubByModel = acc.getVarArgsByModel();
ArgMap constSubByModel = acc.getConstArgsByModel();
Set<ConstraintElement> modelSet = new HashSet<ConstraintElement>();
modelSet.addAll(varSubByModel.keySet());
modelSet.addAll(constSubByModel.keySet());
for (ConstraintElement model: modelSet) {
args.add(constructConstraintExpression(model, varSubByModel.get(model), constSubByModel.get(model)));
}
return new ConstraintConjunction(args);
}
public ConjAccumulator transformConj(SymbolicTransformationContext context, ConstraintConjunction cc, ConjAccumulator acc)
throws SymbolicTransformationException {
for (ConstraintExpression arg: cc.getElements()) {
if (arg instanceof ConstraintConjunction) {
acc = transformConj(context, (ConstraintConjunction)arg, acc);
} else if (arg instanceof ConstraintDisjunction) {
ConstraintExpression expr = transformOperation(context, (ConstraintDisjunction)arg);
acc.accumulate(expr);
} else {
acc.accumulate(arg);
}
}
return acc;
}
/**
* Convenience interface to avoid having to work with the full template pattern of:
* Map<ConstraintElement,Map<ConstraintElement,Map<ConstraintElement,List<ConstraintElement>>>>
*/
private interface ArgMap extends Map<ConstraintElement,Map<ConstraintElement,Map<ConstraintElement,List<ConstraintElement>>>> {
}
/** Convenience class for implementing ArgMap with a HashMap. */
private class ArgHashMap extends HashMap<ConstraintElement,Map<ConstraintElement,Map<ConstraintElement,List<ConstraintElement>>>>
implements ArgMap {
private static final long serialVersionUID = -5787565491022825665L;
}
private class ConjAccumulator {
private SymbolicTransformationContext context;
// Map<ConstraintElement,Map<Variable,Map>> varArgsByModel;
private ArgMap varArgsByModel;
private ArgMap constArgsByModel;
private List<ConstraintExpression> residualArgs;
public ConjAccumulator(SymbolicTransformationContext context) {
this.context = context;
varArgsByModel = new ArgHashMap();
constArgsByModel = new ArgHashMap();
residualArgs = new ArrayList<ConstraintExpression>();
}
public void accumulate(ConstraintExpression arg) throws SymbolicTransformationException {
if (arg instanceof Constraint) {
accumulateConstraint((Constraint)arg);
} else if (arg instanceof ConstraintConjunction) {
throw new IllegalStateException("ConstraintConjunction should have been handled by caller");
} else {
residualArgs.add(arg);
}
}
private void accumulateConstraint(Constraint arg) throws SymbolicTransformationException {
try {
ConstraintElement model = arg.getModel();
if (model instanceof URIReference) {
URIReference cu = (URIReference)model;
URI constraintModelType = context.mapToModelTypeURI(cu.getURI());
if (constraintModelType.equals(modelTypeURI)) {
ConstraintElement subject = arg.getElement(0);
if (subject instanceof Variable) {
insertByModel(model, varArgsByModel, arg);
} else {
insertByModel(model, constArgsByModel, arg);
}
} else {
residualArgs.add(arg);
}
} else {
residualArgs.add(arg);
}
} catch (QueryException eq) {
throw new SymbolicTransformationException("Failed to match model with modeltype", eq);
}
}
private void insertByModel(ConstraintElement model, Map<ConstraintElement,Map<ConstraintElement,Map<ConstraintElement,List<ConstraintElement>>>> target, Constraint arg) {
Map<ConstraintElement,Map<ConstraintElement,List<ConstraintElement>>> bySubject = target.get(model);
if (bySubject == null) {
bySubject = new HashMap<ConstraintElement,Map<ConstraintElement,List<ConstraintElement>>>();
target.put(model, bySubject);
}
Map<ConstraintElement,List<ConstraintElement>> byPredicate = bySubject.get(arg.getElement(0));
if (byPredicate == null) {
byPredicate = new HashMap<ConstraintElement,List<ConstraintElement>>();
bySubject.put(arg.getElement(0), byPredicate);
}
List<ConstraintElement> objects = byPredicate.get(arg.getElement(1));
if (objects == null) {
objects = new ArrayList<ConstraintElement>();
byPredicate.put(arg.getElement(1), objects);
}
objects.add(arg.getElement(2));
}
public boolean isTransformed() {
return (varArgsByModel.size() != 0) || (constArgsByModel.size() != 0);
}
public List<ConstraintExpression> getResidualArgs() {
return residualArgs;
}
public ArgMap getVarArgsByModel() {
return varArgsByModel;
}
public ArgMap getConstArgsByModel() {
return constArgsByModel;
}
}
}