org.openanzo.glitter.syntax.abstrakt.Group.java Source code

Java tutorial

Introduction

Here is the source code for org.openanzo.glitter.syntax.abstrakt.Group.java

Source

/*******************************************************************************
 * Copyright (c) 2004, 2007 IBM Corporation and Cambridge Semantics Incorporated.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * File: $Source: /cvsroot/slrp/glitter/com.ibm.adtech.glitter/src/com/ibm/adtech/glitter/syntax/abstrakt/Group.java,v $
 * Created by:  Lee Feigenbaum (<a href="mailto:feigenbl@us.ibm.com">feigenbl@us.ibm.com</a>)
 * Created on: 10/23/06
 * Revision: $Id: Group.java 164 2007-07-31 14:11:09Z mroy $
 *
 * Contributors: IBM Corporation - initial API and implementation
 *     Cambridge Semantics Incorporated - Fork to Anzo
 *******************************************************************************/
package org.openanzo.glitter.syntax.abstrakt;

import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.apache.commons.collections15.MultiMap;
import org.apache.commons.collections15.multimap.MultiHashMap;
import org.openanzo.exceptions.ExceptionConstants;
import org.openanzo.glitter.exception.GlitterRuntimeException;
import org.openanzo.glitter.query.QueryController;
import org.openanzo.glitter.query.QueryController.QueryStringPrintOptions;
import org.openanzo.rdf.URI;
import org.openanzo.rdf.Variable;

/**
 * A group represents an ordered collection of graph patterns delimited by curly braces in a SPARQL query. A group also contains a set of filters that apply to
 * the bindings generated from the patterns within the group.
 * 
 * @author lee <lee@cambridgesemantics.com>
 * 
 */
public class Group extends GraphPattern {

    private ArrayList<GraphPattern> patterns;

    private HashSet<Expression> filters;

    private MultiHashMap<Variable, Expression> assignments;

    @Override
    public Group clone() {
        ArrayList<GraphPattern> gps = new ArrayList<GraphPattern>();
        for (GraphPattern gp : this.patterns)
            gps.add((GraphPattern) gp.clone());
        return new Group(gps, this.filters, this.assignments);
    }

    /**
     * Default constructor.
     */
    public Group() {
        this.patterns = new ArrayList<GraphPattern>();
        this.filters = new HashSet<Expression>();
        this.assignments = new MultiHashMap<Variable, Expression>();
    }

    /**
     * Construct a group from a list of patterns and a set of filter expressions.
     * 
     * @param patterns
     * @param filters
     * @param assignments
     */
    @SuppressWarnings("unchecked")
    public Group(ArrayList<GraphPattern> patterns, HashSet<Expression> filters,
            MultiHashMap<Variable, Expression> assignments) {
        this.patterns = new ArrayList<GraphPattern>();
        for (GraphPattern gp : patterns) {
            this.patterns.add((GraphPattern) gp.clone());
        }
        this.filters = (HashSet<Expression>) filters.clone();
        this.assignments = (MultiHashMap<Variable, Expression>) assignments.clone();
        for (GraphPattern gp : this.patterns)
            gp.setParent(this);
    }

    /**
     * Construct a group with no filters from a list of graph patterns.
     * 
     * @param patterns
     *            graph patterns to add to group
     */
    public Group(ArrayList<GraphPattern> patterns) {
        this.patterns = new ArrayList<GraphPattern>();
        for (GraphPattern gp : patterns) {
            this.patterns.add((GraphPattern) gp.clone());
        }
        this.filters = new HashSet<Expression>();
        this.assignments = new MultiHashMap<Variable, Expression>();
        for (GraphPattern gp : this.patterns)
            gp.setParent(this);
    }

    /**
     * Remove the given filter from this group.
     * 
     * @param f
     *            expression to remove from group
     * @return true if given filter was removed from this group.
     */
    public boolean removeFilter(Expression f) {
        invalidateCache();
        return this.filters.remove(f);
    }

    /**
     * Remove all filters from this group.
     */
    private void removeAllFilters() {
        invalidateCache();
        this.filters.clear();
    }

    /**
     * Add the given filter to this group.
     * 
     * @param f
     *            expression to add group
     */
    public void addFilter(Expression f) {
        this.filters.add(f);
        invalidateCache();
    }

    @Override
    public Set<Expression> getFilters() {
        return this.filters;
    }

    /**
     * Remove the given assignment (variable, expression) pair from this group.
     * 
     * @param v
     * @param e
     * 
     * @return true if given assignment was removed from this group.
     */
    public boolean removeAssignment(Variable v, Expression e) {
        invalidateCache();
        return this.assignments.remove(v, e) != null;
    }

    /**
     * Removes all assignments to a given variable attached to this group
     * 
     * @param v
     * @return true if any assignments were removed from this group
     */
    public boolean removeVariableAssignments(Variable v) {
        invalidateCache();
        return this.assignments.remove(v) != null;
    }

    /**
     * Remove all assignments from this group.
     */
    private void removeAllAssignments() {
        invalidateCache();
        this.assignments.clear();
    }

    /**
     * Add the given assignment to this group.
     * 
     * @param v
     * @param e
     *            the variable and expression to add as an assignment
     */
    public void addAssignment(Variable v, Expression e) {
        invalidateCache();
        this.assignments.put(v, e);
    }

    /**
     * 
     * @return The assignments associated with this group.
     */
    public MultiMap<Variable, Expression> getAssignments() {
        return this.assignments;
    }

    /**
     * Removes the given graph pattern from this group.
     * 
     * @param gp
     *            graph pattern to remove from group
     * @return true if given patern was removed from the group
     */
    public boolean removeGraphPattern(GraphPattern gp) {
        boolean b = this.patterns.remove(gp);
        if (b)
            gp.setParent(null);
        return b;
    }

    /**
     * Adds the given graph pattern to this group.
     * 
     * @param gp
     *            graph pattern to add to group
     */
    public void addGraphPattern(GraphPattern gp) {
        this.patterns.add(gp);
        gp.setParent(this);
    }

    /**
     * Add all the graph patterns from another {@link Group} to this group.
     * 
     * @param other
     *            source group from which all patterns will be added to this group
     */
    public void addPatternsFrom(Group other) {
        for (GraphPattern gp : other.getPatterns())
            this.addGraphPattern(gp);
    }

    /**
     * Get an iterable collection of this group's graph patterns
     * 
     * @return an iterable collection of this group's graph patterns
     */
    public Collection<GraphPattern> getPatterns() {
        return this.patterns;
    }

    /**
     * Transforms the current patterns that comprise this group into the first parameter to an {@link Optional} construct, with <tt>mayMatch</tt> as the second.
     * Replaces those patterns with the optional as the only pattern in this group.
     * 
     * @param mayMatch
     *            The optional part of the new optional.
     */
    public void replaceCurrentContentsWithOptional(Group mayMatch) {
        /*
          Optional opt = null;
          if (this.patterns.size() > 0) {
             opt = new Optional(this.patterns.get(this.patterns.size() - 1), mayMatch, mayMatch.getFilters());
             this.patterns.remove(this.patterns.size() - 1);
             mayMatch.removeAllFilters();
          } else {
             opt = new Optional(mayMatch);
          }
          addGraphPattern(opt);
        */
        // if we don't have any patterns yet, just add in an optional
        Optional opt = null;
        if (this.patterns.size() == 0) {
            opt = new Optional(mayMatch);
        } else {
            // filters & assignments must stay attached to the current group, not to the group inside the optional
            Group mustMatch = this.clone();
            mustMatch.removeAllFilters();
            mustMatch.removeAllAssignments();
            opt = new Optional(mustMatch, mayMatch, mayMatch.getFilters());
            mayMatch.removeAllFilters();
            this.patterns = new ArrayList<GraphPattern>();
        }

        // add in the optional
        addGraphPattern(opt);
    }

    public void prettyPrintQueryPart(EnumSet<QueryStringPrintOptions> printFlags, int indentLevel,
            Map<String, String> uri2prefix, StringBuilder s) {
        for (int i = 0; i < this.patterns.size(); i++) {
            if (i > 0) {
                if (patterns.get(i - 1) instanceof BGP) {
                    s.append(". ");
                }
                QueryController.printSeparator(printFlags, indentLevel, s);
            }
            GraphPattern gp = this.patterns.get(i);
            if (gp instanceof Group) {
                s.append("{");
                indentLevel++;
                QueryController.printSeparator(printFlags, indentLevel, s);
            }
            gp.prettyPrintQueryPart(printFlags, indentLevel, uri2prefix, s);
            if (gp instanceof Group) {
                indentLevel--;
                QueryController.printSeparator(printFlags, indentLevel, s);
                s.append("}");
            }
        }
        if (assignments.size() > 0) {
            for (Entry<Variable, Collection<Expression>> assignment : assignments.entrySet()) {
                Variable v = assignment.getKey();
                for (Expression e : assignment.getValue()) {
                    QueryController.printSeparator(printFlags, indentLevel, s);
                    s.append(" LET (");
                    s.append(v.toString());
                    s.append(" := ");
                    e.prettyPrintQueryPart(printFlags, indentLevel, uri2prefix, s);
                    s.append(")");
                }
            }
        }
        if (filters.size() > 0) {
            for (Expression filter : filters) {
                QueryController.printSeparator(printFlags, indentLevel, s);
                s.append("FILTER (");
                filter.prettyPrintQueryPart(printFlags, indentLevel, uri2prefix, s);
                s.append(")");
            }
        }
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        //builder.append("{ ");
        for (int i = 0; i < this.patterns.size(); i++) {
            if (i > 0)
                builder.append(" ");
            GraphPattern gp = this.patterns.get(i);
            if (gp instanceof Group)
                builder.append("{ ");
            builder.append(gp);
            if (gp instanceof Group)
                builder.append(" }");
        }

        if (assignments.size() > 0) {
            for (Entry<Variable, Collection<Expression>> assignment : assignments.entrySet()) {
                Variable v = assignment.getKey();
                for (Expression e : assignment.getValue()) {
                    builder.append(" LET (");
                    builder.append(v.toString());
                    builder.append(" := ");
                    builder.append(e.toString());
                    builder.append(")");
                }
            }
        }

        if (filters.size() > 0) {
            for (Expression filter : filters) {
                builder.append(" FILTER (");
                builder.append(filter.toString());
                builder.append(")");
            }
        }
        //builder.append(" }");

        return builder.toString();
    }

    @Override
    public List<GraphPattern> getChildren() {
        return this.patterns;
    }

    @Override
    public boolean replaceChild(TreeNode oldChild, TreeNode newChild) {
        if (newChild instanceof GraphPattern) {
            for (ListIterator<GraphPattern> it = this.patterns.listIterator(); it.hasNext();) {
                GraphPattern cur = it.next();
                if (oldChild == cur) {
                    oldChild.setParent(null);
                    newChild.setParent(this);
                    it.set((GraphPattern) newChild);
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    protected Map<Variable, Integer> getVariableCount(boolean onlyBindableVariables) {
        Map<Variable, Integer> vars = super.getVariableCount(onlyBindableVariables);
        // include variables on the LHS of LET-expressions
        for (Variable v : this.assignments.keySet())
            incrementVariableCount(vars, v, 1);
        // if we want all variables, regardless of whether they can be bound to,
        // we also include variables occuring inside filters and the RHS of LET-expressions
        if (!onlyBindableVariables) {
            for (Expression e : this.filters)
                for (Variable v : e.getReferencedVariables())
                    incrementVariableCount(vars, v, 1);
            for (Expression e : this.assignments.values())
                for (Variable v : e.getReferencedVariables())
                    incrementVariableCount(vars, v, 1);
        }
        return vars;
    }

    @Override
    public Collection<URI> getReferencedURIs() {
        Collection<URI> uris = super.getReferencedURIs();
        for (Expression e : this.filters)
            uris.addAll(e.getReferencedURIs());
        for (Expression e : this.assignments.values())
            uris.addAll(e.getReferencedURIs());
        return uris;
    }

    @Override
    public boolean removeChild(TreeNode child) {
        if (this.patterns.remove(child))
            return true;
        return (child instanceof Expression && this.filters.remove(child));
    }

    @Override
    public void addChild(TreeNode child) {
        if (child instanceof GraphPattern) {
            addGraphPattern((GraphPattern) child);
        } else
            throw new GlitterRuntimeException(ExceptionConstants.GLITTER.ONLY_ADD, "GraphPattern", "Group Query");
    }

    @Override
    protected boolean prettyPrintParams(StringBuilder output) {
        boolean printedSomething = false;
        if (filters.size() > 0) {
            output.append("Filters(");
            int i = 0;
            for (Expression filter : filters) {

                filter.prettyPrint(output);

                if (++i < filters.size())
                    output.append(", ");
            }
            output.append(")");
            printedSomething = true;
        }
        if (assignments.size() > 0) {
            output.append("Assignments(");
            int i = 0;
            int size = assignments.totalSize();
            for (Entry<Variable, Collection<Expression>> assignment : assignments.entrySet()) {
                Variable v = assignment.getKey();
                for (Expression e : assignment.getValue()) {
                    output.append(v.toString());
                    output.append(" := ");
                    e.prettyPrint(output);
                    if (++i < size)
                        output.append(", ");
                }
            }
            output.append(")");
            printedSomething = true;
        }

        return printedSomething;
    }
}