/*
* Copyright (c) 2013-2015 Josef Hardi <josef.hardi@gmail.com>
*
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.obidea.semantika.knowledgebase.processor;
import java.util.ArrayList;
import java.util.List;
import com.obidea.semantika.database.sql.base.ISqlExpression;
import com.obidea.semantika.database.sql.base.SqlSelectItem;
import com.obidea.semantika.expression.base.AbstractFunction;
import com.obidea.semantika.expression.base.Atom;
import com.obidea.semantika.expression.base.AtomVisitorAdapter;
import com.obidea.semantika.expression.base.IAtom;
import com.obidea.semantika.expression.base.IConstant;
import com.obidea.semantika.expression.base.IFunction;
import com.obidea.semantika.expression.base.ILiteral;
import com.obidea.semantika.expression.base.IRule;
import com.obidea.semantika.expression.base.ITerm;
import com.obidea.semantika.expression.base.IUriReference;
import com.obidea.semantika.expression.base.IVariable;
import com.obidea.semantika.expression.base.TermUtils;
import com.obidea.semantika.knowledgebase.TermSubstitutionBinding;
import com.obidea.semantika.knowledgebase.UnificationException;
import com.obidea.semantika.knowledgebase.Unifier;
import com.obidea.semantika.mapping.IUriTemplate;
import com.obidea.semantika.mapping.base.IMapping;
import com.obidea.semantika.mapping.base.TripleAtom;
import com.obidea.semantika.mapping.base.sql.SqlJoin;
import com.obidea.semantika.mapping.base.sql.SqlQuery;
import com.obidea.semantika.mapping.base.sql.SqlSubQuery;
import com.obidea.semantika.util.Serializer;
public class MappingContainmentChecker
{
public static boolean isContained(IMapping sourceMapping, IMapping targetMapping, List<IRule> constraintRules) throws MappingContaimentCheckException
{
validateMapping(sourceMapping);
validateMapping(targetMapping);
/*
* Freezing triple atom from mapping head (Note: possible terms are variables, constant or URI
* template function).
*/
IAtom sourceFact = freeze(sourceMapping.getHead());
/*
* Freezing SQL table atom from mapping body (Note: all terms are variables).
*/
IAtom tableFact = freeze(sourceMapping.getBody().get(0));
for (IRule rule : constraintRules) {
try {
TripleAtom mappingHead = (TripleAtom) Serializer.copy(targetMapping.getHead());
TermSubstitutionBinding theta = TermSubstitutionBinding.createEmptyBinding();
Unifier.findSubstitution(tableFact, rule.getBody().get(0), theta);
mappingHead.apply(theta);
IAtom targetFact = freeze(mappingHead);
if (targetFact.equals(sourceFact)) {
return true;
}
}
catch (UnificationException e) {
continue; // continue to the next rule if unifier is not found
}
}
return false;
}
public static IAtom freeze(IAtom atom)
{
final List<IConstant> constantList = new ArrayList<IConstant>();
atom.accept(new AtomVisitorAdapter()
{
@Override
public void visit(IAtom atom)
{
for (ITerm term : atom.getTerms()) {
term.accept(this);
}
}
@Override
public void visit(IFunction function)
{
if (function instanceof IUriTemplate) {
IUriTemplate uriTemplate = (IUriTemplate) function;
List<IConstant> templateArgs = new ArrayList<IConstant>();
for (ITerm term : uriTemplate.getParameters()) {
if (term instanceof IVariable) {
templateArgs.add(TermUtils.makePlainLiteral(term.getName()));
}
else if (term instanceof IConstant) {
templateArgs.add((IConstant) term);
}
}
IUriReference uriConstant = uriTemplate.execute(templateArgs);
constantList.add(uriConstant);
}
else {
// NO-OP: Should never go here
}
}
@Override
public void visit(IUriReference uriReference)
{
constantList.add(uriReference);
}
@Override
public void visit(ILiteral literal)
{
constantList.add(literal);
}
@Override
public void visit(IVariable variable)
{
constantList.add(TermUtils.makePlainLiteral(variable.getName()));
}
});
return new Atom(atom.getPredicate(), constantList);
}
private static void validateMapping(IMapping mapping) throws MappingContaimentCheckException
{
SqlQuery sourceQuery = mapping.getSourceQuery();
/*
* MCC doesn't apply when the source query has built-in functions in its column projection
*/
for (SqlSelectItem selectItem : sourceQuery.getSelectItems()) {
ISqlExpression expression = selectItem.getExpression();
if (expression instanceof AbstractFunction) {
String message = String.format("Source query contains column expression '%s'", expression); //$NON-NLS-1$
throw new MappingContaimentCheckException(mapping, message);
}
}
/*
* MCC doesn't apply for JOIN query or sub-queries.
*/
ISqlExpression tableExpression = sourceQuery.getFromExpression();
if (tableExpression instanceof SqlJoin) {
throw new MappingContaimentCheckException(mapping, "Source query contains SQL JOIN expression"); //$NON-NLS-1$
}
else if (tableExpression instanceof SqlSubQuery) {
throw new MappingContaimentCheckException(mapping, "Source query contains sub-query expression"); //$NON-NLS-1$
}
/*
* MCC doesn't apply when the source query has filters.
*/
if (sourceQuery.hasWhereExpression()) {
throw new MappingContaimentCheckException(mapping, "Source query contains SQL WHERE expression"); //$NON-NLS-1$
}
}
}