You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stanbol.apache.org by rw...@apache.org on 2013/10/14 15:47:29 UTC

svn commit: r1531896 [2/2] - in /stanbol/trunk/entityhub/query: clerezza/ clerezza/src/main/java/org/apache/stanbol/entityhub/query/clerezza/ clerezza/src/test/java/org/apache/stanbol/entityhub/query/clerezza/ sparql/ sparql/src/ sparql/src/main/ sparq...

Added: stanbol/trunk/entityhub/query/sparql/src/main/java/org/apache/stanbol/entityhub/query/sparql/SparqlFieldQuery.java
URL: http://svn.apache.org/viewvc/stanbol/trunk/entityhub/query/sparql/src/main/java/org/apache/stanbol/entityhub/query/sparql/SparqlFieldQuery.java?rev=1531896&view=auto
==============================================================================
--- stanbol/trunk/entityhub/query/sparql/src/main/java/org/apache/stanbol/entityhub/query/sparql/SparqlFieldQuery.java (added)
+++ stanbol/trunk/entityhub/query/sparql/src/main/java/org/apache/stanbol/entityhub/query/sparql/SparqlFieldQuery.java Mon Oct 14 13:47:28 2013
@@ -0,0 +1,220 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.stanbol.entityhub.query.sparql;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.stanbol.entityhub.core.query.FieldQueryImpl;
+import org.apache.stanbol.entityhub.servicesapi.query.FieldQuery;
+
+/**
+ * Adds the "selected field" to "SPARQL variable name" mapping
+ * 
+ * @author Rupert Westenthaler
+ * 
+ */
+public class SparqlFieldQuery extends FieldQueryImpl implements FieldQuery, Cloneable {
+    /**
+     * String used as prefix for variables generated for fields
+     */
+    protected static final String FIELD_VAR_PREFIX = "v_";
+    protected static final String ROOT_VAR_NAME = "id";
+    protected int varNum;
+    protected final Map<String,String> field2VarMappings;
+    protected final Map<String,String> unmodField2VarMappings;
+    protected SparqlEndpointTypeEnum endpointType;
+
+    protected SparqlFieldQuery() {
+        this(null);
+    }
+
+    protected SparqlFieldQuery(SparqlEndpointTypeEnum endpointType) {
+        super();
+        this.endpointType = endpointType != null ? endpointType : SparqlEndpointTypeEnum.Standard;
+        varNum = 0;
+        field2VarMappings = new HashMap<String,String>();
+        unmodField2VarMappings = Collections.unmodifiableMap(field2VarMappings);
+    }
+
+    public final SparqlEndpointTypeEnum getSparqlEndpointType() {
+        return endpointType;
+    }
+
+    public final void setSparqlEndpointType(SparqlEndpointTypeEnum endpointType) {
+        this.endpointType = endpointType;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.stanbol.entityhub.core.query.FieldQueryImpl#addSelectedField (java.lang.String)
+     */
+    @Override
+    public void addSelectedField(String field) {
+        super.addSelectedField(field);
+        field2VarMappings.put(field, getFieldVar());
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.stanbol.entityhub.core.query.FieldQueryImpl#addSelectedFields (java.util.Collection)
+     */
+    @Override
+    public void addSelectedFields(Collection<String> fields) {
+        super.addSelectedFields(fields);
+        for (String field : fields) {
+            field2VarMappings.put(field, getFieldVar());
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.stanbol.entityhub.core.query.FieldQueryImpl#removeSelectedField (java.lang.String)
+     */
+    @Override
+    public void removeSelectedField(String field) {
+        super.removeSelectedField(field);
+        field2VarMappings.remove(field);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.stanbol.entityhub.core.query.FieldQueryImpl#removeSelectedFields (java.util.Collection)
+     */
+    @Override
+    public void removeSelectedFields(Collection<String> fields) {
+        super.removeSelectedFields(fields);
+        for (String field : fields) {
+            field2VarMappings.remove(field);
+        }
+    }
+
+    /**
+     * Getter for the variable name for a selected field
+     * 
+     * @param field
+     *            the selected field
+     * @return the variable name or <code>null</code> if the parsed field is not selected.
+     */
+    public String getVariableName(String field) {
+        return field2VarMappings.get(field);
+    }
+
+    /**
+     * Getter for the unmodifiable field name to variable name mapping.
+     * 
+     * @return
+     */
+    public Map<String,String> getFieldVariableMappings() {
+        return unmodField2VarMappings;
+    }
+
+    private String getFieldVar() {
+        varNum++;
+        return FIELD_VAR_PREFIX + varNum;
+    }
+
+    public String getRootVariableName() {
+        return ROOT_VAR_NAME;
+    }
+
+    /**
+     * Clones the query (including the field to var name mapping)
+     */
+    @Override
+    public SparqlFieldQuery clone() {
+        return clone(new SparqlFieldQuery());
+    }
+    /**
+     * can be used by sub-classes to implement {@link #clone()}   
+     * @param emptyClone an empty instance of the sub class
+     * @return the parsed instance set will the state of this class. NOTE:
+     * state of sub-classes need still to be set
+     */
+    protected final <T extends SparqlFieldQuery> T clone(T emptyClone){
+        T clone = super.copyTo(emptyClone);
+        // Note: this uses the public API. However the field->ar mapping might
+        // still
+        // be different if any removeSelectedField(..) method was used on this
+        // instance. Because of that manually set the map and the value of the
+        // int.
+        // clone.field2VarMappings.clear(); //clear is not necessary, because
+        // the keys are equals!
+        clone.field2VarMappings.putAll(field2VarMappings);
+        clone.varNum = varNum;
+        return clone;
+    }
+
+    @Override
+    public int hashCode() {
+        return super.hashCode() + field2VarMappings.hashCode() + varNum + endpointType.ordinal();
+    }
+
+    /**
+     * Removes also the field to var name mappings
+     * 
+     * @see org.apache.stanbol.entityhub.core.query.FieldQueryImpl#removeAllSelectedFields()
+     */
+    @Override
+    public void removeAllSelectedFields() {
+        super.removeAllSelectedFields();
+        field2VarMappings.clear();
+        varNum = 0;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return super.equals(obj) && obj instanceof SparqlFieldQuery
+               && ((SparqlFieldQuery) obj).field2VarMappings.equals(field2VarMappings)
+               && ((SparqlFieldQuery) obj).varNum == varNum
+               && ((SparqlFieldQuery) obj).endpointType == endpointType;
+    }
+
+    /**
+     * Getter for the SPARQL SELECT representation of this FieldQuery
+     * 
+     * @return the SPARQL SELECT query
+     */
+    public String toSparqlSelect(boolean includeFields) {
+        return SparqlQueryUtils.createSparqlSelectQuery(this, includeFields, endpointType);
+    }
+
+    /**
+     * Getter for the SPARQL CONSTRUCT representation of this FieldQuery
+     * 
+     * @return the SPARQL CONSTRUCT query
+     */
+    public String toSparqlConstruct() {
+        return SparqlQueryUtils.createSparqlConstructQuery(this, endpointType);
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + " field->variable mappings: " + field2VarMappings;
+    }
+
+    public SparqlFieldQuery createFieldQuery() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+}

Added: stanbol/trunk/entityhub/query/sparql/src/main/java/org/apache/stanbol/entityhub/query/sparql/SparqlFieldQueryFactory.java
URL: http://svn.apache.org/viewvc/stanbol/trunk/entityhub/query/sparql/src/main/java/org/apache/stanbol/entityhub/query/sparql/SparqlFieldQueryFactory.java?rev=1531896&view=auto
==============================================================================
--- stanbol/trunk/entityhub/query/sparql/src/main/java/org/apache/stanbol/entityhub/query/sparql/SparqlFieldQueryFactory.java (added)
+++ stanbol/trunk/entityhub/query/sparql/src/main/java/org/apache/stanbol/entityhub/query/sparql/SparqlFieldQueryFactory.java Mon Oct 14 13:47:28 2013
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.stanbol.entityhub.query.sparql;
+
+import org.apache.stanbol.entityhub.servicesapi.query.FieldQuery;
+import org.apache.stanbol.entityhub.servicesapi.query.FieldQueryFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class SparqlFieldQueryFactory implements FieldQueryFactory {
+
+    private static SparqlFieldQueryFactory instance;
+
+    public static SparqlFieldQueryFactory getInstance() {
+        if (instance == null) {
+            instance = new SparqlFieldQueryFactory();
+        }
+        return instance;
+    }
+
+    private SparqlFieldQueryFactory() {
+        super();
+    }
+
+    @Override
+    public SparqlFieldQuery createFieldQuery() {
+        return new SparqlFieldQuery();
+    }
+
+    /**
+     * Utility Method to create an {@link SparqlFieldQuery} based on the parse {@link FieldQuery}
+     * 
+     * @param parsedQuery
+     *            the parsed Query
+     */
+    public static SparqlFieldQuery getSparqlFieldQuery(FieldQuery parsedQuery) {
+        Logger logger = LoggerFactory.getLogger(SparqlFieldQueryFactory.class);
+
+        if (parsedQuery == null) {
+            logger.trace("Parsed query is null.");
+            return null;
+        } else if (parsedQuery instanceof SparqlFieldQuery) {
+            logger.trace("Parsed query is a [SparqlFieldQuery].");
+            return (SparqlFieldQuery) parsedQuery;
+        } else {
+            logger.trace("Parsed query is a [{}].", parsedQuery.getClass().toString());
+            return parsedQuery.copyTo(new SparqlFieldQuery());
+        }
+    }
+
+}

Added: stanbol/trunk/entityhub/query/sparql/src/main/java/org/apache/stanbol/entityhub/query/sparql/SparqlQueryUtils.java
URL: http://svn.apache.org/viewvc/stanbol/trunk/entityhub/query/sparql/src/main/java/org/apache/stanbol/entityhub/query/sparql/SparqlQueryUtils.java?rev=1531896&view=auto
==============================================================================
--- stanbol/trunk/entityhub/query/sparql/src/main/java/org/apache/stanbol/entityhub/query/sparql/SparqlQueryUtils.java (added)
+++ stanbol/trunk/entityhub/query/sparql/src/main/java/org/apache/stanbol/entityhub/query/sparql/SparqlQueryUtils.java Mon Oct 14 13:47:28 2013
@@ -0,0 +1,1160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.stanbol.entityhub.query.sparql;
+
+import static org.apache.stanbol.entityhub.servicesapi.defaults.SpecialFieldEnum.isSpecialField;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.stanbol.entityhub.core.utils.TimeUtils;
+import org.apache.stanbol.entityhub.servicesapi.defaults.DataTypeEnum;
+import org.apache.stanbol.entityhub.servicesapi.model.Reference;
+import org.apache.stanbol.entityhub.servicesapi.model.rdf.RdfResourceEnum;
+import org.apache.stanbol.entityhub.servicesapi.query.Constraint;
+import org.apache.stanbol.entityhub.servicesapi.query.RangeConstraint;
+import org.apache.stanbol.entityhub.servicesapi.query.TextConstraint;
+import org.apache.stanbol.entityhub.servicesapi.query.TextConstraint.PatternType;
+import org.apache.stanbol.entityhub.servicesapi.query.ValueConstraint;
+import org.apache.stanbol.entityhub.servicesapi.query.ValueConstraint.MODE;
+import org.apache.stanbol.entityhub.servicesapi.util.PatternUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility Class to create SPARQL Queries for {@link SparqlFieldQuery} instances.
+ * <p>
+ * Thanks to ogrisel for pointing me to his <a href=
+ * "http://hg.nuxeo.org/sandbox/scribo/raw-file/b57ada956947/scribo-annotator-recognizer-sparql-ep/src/main/java/ws/scribo/annotators/recognizer/SparqlEndpointInstanceRecognizer.java"
+ * > SparqlEndpointInstanceRecognizer</a> implementation for the query optimisations for Virtuoso and LARQ!
+ * 
+ * @author Rupert Westenthaler
+ * 
+ */
+public final class SparqlQueryUtils {
+
+    private static final Logger log = LoggerFactory.getLogger(SparqlQueryUtils.class);
+
+    private static final String XSD_DATE_TIME = "http://www.w3.org/2001/XMLSchema#dateTime";
+    //private static final DateFormat DATE_FORMAT = new W3CDateFormat();
+
+    private SparqlQueryUtils() {}
+
+    /**
+     * Creates a SPARWL CONSTRUCT query that creates triples for all the selected fields of representations in
+     * the result set.
+     * <p>
+     * In addition the query also constructs <code>entityhub-query:ieldQueryResultSet
+     * entityhub-query:fieldQueryResult ?representation </code> triples that can be used to create an iterator
+     * over the results of the query
+     * 
+     * @param query
+     *            the field query
+     * @param endpointType
+     *            The type of the Endpoint (used to write optimized queries for endpoint type specific
+     *            extensions
+     * @param additionalFields
+     *            This allows to parse additional fields that are optionally selected in the data set and
+     *            added to the CONSTRUCT part of the query
+     * @return the SPARQL CONSTRUCT Query
+     */
+    public static String createSparqlConstructQuery(SparqlFieldQuery query,
+                                                    SparqlEndpointTypeEnum endpointType,
+                                                    String... additionalFields) {
+        return createSparqlConstructQuery(query, -1, endpointType, additionalFields);
+    }
+
+    /**
+     * Creates a SPARWL CONSTRUCT query that creates triples for all the selected fields of representations in
+     * the result set.
+     * <p>
+     * In addition the query also constructs <code>entityhub-query:ieldQueryResultSet
+     * entityhub-query:fieldQueryResult ?representation </code> triples that can be used to create an iterator
+     * over the results of the query
+     * 
+     * @param query
+     *            the field query
+     * @param limit
+     *            if a value > 0 is parsed, than this value overwrites the limit defined by the query.
+     * @param endpointType
+     *            The type of the Endpoint (used to write optimized queries for endpoint type specific
+     *            extensions
+     * @param additionalFields
+     *            This allows to parse additional fields that are optionally selected in the data set and
+     *            added to the CONSTRUCT part of the query
+     * @return the SPARQL CONSTRUCT Query
+     */
+    public static String createSparqlConstructQuery(SparqlFieldQuery query,
+                                                    int limit,
+                                                    SparqlEndpointTypeEnum endpointType,
+                                                    String... additionalFields) {
+        // 1)INIT
+        final StringBuilder queryString = new StringBuilder();
+        // clone the query and reconfigure the clone
+        query = initLocalQuery(query, limit, additionalFields);
+        final Map<String,String> selectedFields = initSelectedFieldsMap(query);
+        // 2)CONSTRUCT
+        createConstruct(queryString, selectedFields);
+        // 3)WHERE
+        queryString.append("WHERE { \n");
+        addFieldConstraint(queryString, query, selectedFields, endpointType);
+        queryString.append("} \n");
+        // 5) Limit and Offset
+        if (!isSubSelectState(endpointType, selectedFields)) {
+            // 4)add Entity Ranking (if needed)
+            addRankingOrder(endpointType, queryString, selectedFields.get(null), "");
+            addLimit(query.getLimit() != null ? query.getLimit() : 0, queryString);
+            addOffset(query, queryString);
+        }
+        return queryString.toString();
+    }
+
+    /**
+     * Determines if the current query uses sub selects. Activated if the SPARQL endpoint supports the SPARQL
+     * 1.1 sub select feature and the query selects more than the enttiy id.
+     * 
+     * @param endpoint
+     *            the used endpoint type
+     * @param selectedFields
+     *            the map with the selected fields
+     * @return the state
+     */
+    private static boolean isSubSelectState(SparqlEndpointTypeEnum endpoint, Map<String,String> selectedFields) {
+        return endpoint.supportsSubSelect() && selectedFields.size() > 1;
+    }
+
+    /**
+     * Creates a clone of the parsed query and applies the parsed limit and additional fields
+     * 
+     * @param query
+     *            the query
+     * @param limit
+     *            the limit (if &gt; 0)
+     * @param additionalFields
+     *            additional fields to select
+     * @return a clone of the parsed query with the set limit and added fields
+     */
+    private static SparqlFieldQuery initLocalQuery(SparqlFieldQuery query,
+                                                   int limit,
+                                                   String... additionalFields) {
+        query = query.clone();
+        if (limit > 0) {
+            query.setLimit(limit);
+        }
+        // We need a copy to delete all fields that are already covered by some
+        // added
+        // graph pattern.
+        if (additionalFields != null && additionalFields.length > 0) {
+            query.addSelectedFields(Arrays.asList(additionalFields));
+        }
+        return query;
+    }
+
+    /**
+     * Creates the CONSTRUCT part of the query including the
+     * <code>entityhub-query:ieldQueryResultSet entityhub-query:fieldQueryResult ?representation </code>
+     * triples that are used to build the iterator over the results
+     * 
+     * @param queryString
+     *            The query to add the construct fields
+     * @param selectedFields
+     *            the field name 2 variable name mapping used by the query. This mapping MUST also contain the
+     *            <code>null</code> key that is mapped to the variable name used for the representations to be
+     *            selected
+     */
+    private static void createConstruct(final StringBuilder queryString,
+                                        final Map<String,String> selectedFields) {
+        queryString.append("CONSTRUCT { \n");
+        String rootVar = selectedFields.get(null);// the null element has the
+                                                  // root variable mapping
+        for (Entry<String,String> mapping : selectedFields.entrySet()) {
+            if (mapping.getKey() != null) {
+                queryString.append("  ?").append(rootVar).append(" <");
+                queryString.append(mapping.getKey()).append("> ?");
+                queryString.append(mapping.getValue()).append(" .\n");
+            }
+        }
+        // add the triples for the Representation type
+        // add the triples that form the result set
+        queryString.append("  <").append(RdfResourceEnum.QueryResultSet).append("> <");
+        queryString.append(RdfResourceEnum.queryResult).append("> ?");
+        queryString.append(rootVar).append(" . \n");
+
+        queryString.append("} ");
+    }
+
+    /**
+     * Creates the SPARQL representation of the parse field query.
+     * 
+     * @param query
+     *            A field query implementation that additionally supports a field to variable mapping
+     * @param endpointType
+     *            The type of the Endpoint (used to write optimized queries for endpoint type specific
+     *            extensions
+     * @return the SPARQL query as String
+     */
+    public static String createSparqlSelectQuery(SparqlFieldQuery query, SparqlEndpointTypeEnum endpointType) {
+        return createSparqlSelectQuery(query, true, -1, endpointType);
+    }
+
+    /**
+     * Creates the SPARQL representation of the parse field query.
+     * 
+     * @param query
+     *            A field query implementation that additionally supports a field to variable mapping
+     * @param limit
+     *            If > 0, than the limit parsed by the query is overriden by this value
+     * @param endpointType
+     *            The type of the Endpoint (used to write optimized queries for endpoint type specific
+     *            extensions
+     * @return the SPARQL query as String
+     */
+    public static String createSparqlSelectQuery(SparqlFieldQuery query,
+                                                 int limit,
+                                                 SparqlEndpointTypeEnum endpointType) {
+        return createSparqlSelectQuery(query, true, limit, endpointType);
+    }
+
+    /**
+     * Creates the SPARQL representation of the parse field query.
+     * 
+     * @param query
+     *            A field query implementation that additionally supports a field to variable mapping
+     * @param includeFields
+     *            if <code>false</code> only the root is selected (selected fields are ignored)
+     * @param endpointType
+     *            The type of the Endpoint (used to write optimized queries for endpoint type specific
+     *            extensions
+     * @return the SPARQL query as String
+     */
+    public static String createSparqlSelectQuery(SparqlFieldQuery query,
+                                                 boolean includeFields,
+                                                 SparqlEndpointTypeEnum endpointType) {
+        return createSparqlSelectQuery(query, includeFields, -1, endpointType);
+    }
+
+    /**
+     * Creates the SPARQL representation of the parse field query.
+     * 
+     * @param query
+     *            A field query implementation that additionally supports a field to variable mapping
+     * @param includeFields
+     *            if <code>false</code> only the root is selected (selected fields are ignored)
+     * @param limit
+     *            if > 0 than the limit defined by the query is overridden by the parsed value
+     * @param endpointType
+     *            The type of the Endpoint (used to write optimized queries for endpoint type specific
+     *            extensions
+     * @return the SPARQL query as String
+     */
+    public static String createSparqlSelectQuery(SparqlFieldQuery query,
+                                                 boolean includeFields,
+                                                 int limit,
+                                                 SparqlEndpointTypeEnum endpointType) {
+        // 1) INIT
+        final StringBuilder queryString = new StringBuilder();
+        query = initLocalQuery(query, limit);
+        final Map<String,String> selectedFields = initSelectedFieldsMap(query);
+        // 2) SELECT
+        createSelect(queryString, includeFields, selectedFields);
+        // 3) WHERE
+        queryString.append("WHERE { \n");
+        addFieldConstraint(queryString, query, selectedFields, endpointType);
+
+        log.trace("After adding field constrains the query string is [{}].", queryString);
+
+        queryString.append("} \n");
+        if (!isSubSelectState(endpointType, selectedFields)) {
+            // 4) Add Stuff to rank results based on the "page rank" of entities
+            addRankingOrder(endpointType, queryString, selectedFields.get(null), "");
+            // 5) Limit and Offset
+            addLimit(query.getLimit() != null ? query.getLimit() : 0, queryString);
+            addOffset(query, queryString);
+        }
+        return queryString.toString();
+    }
+
+    /**
+     * Initialise the field -&gt; variable name mappings including the root variable name by adding
+     * <code>null</code> as key
+     * 
+     * @param query
+     *            the query
+     * @return the mappings
+     */
+    private static Map<String,String> initSelectedFieldsMap(SparqlFieldQuery query) {
+        // We need a copy to delete all fields that are already covered by some
+        // added
+        // graph pattern.
+        final Map<String,String> selectedFields = new HashMap<String,String>();
+        selectedFields.putAll(query.getFieldVariableMappings());
+        // also add the root variable
+        selectedFields.put(null, query.getRootVariableName());
+        return selectedFields;
+    }
+
+    /**
+     * For some {@link SparqlEndpointTypeEnum SPARQL endpoint types} we need to add an additional constraint to
+     * determine the ranking information based on incoming relations to the Entities.
+     * <p>
+     * Currently this done for {@link SparqlEndpointTypeEnum#ARQ ARQ} and {@link SparqlEndpointTypeEnum#LARQ LARQ}.
+     * 
+     * @param endpointType
+     *            the endpoint type
+     * @param queryString
+     *            the SPARQL query string to add the ranking constraint
+     * @param rootFieldName
+     *            the variable name used to select entities
+     */
+    private static void addRankingConstraints(SparqlEndpointTypeEnum endpointType,
+                                              final StringBuilder queryString,
+                                              final String rootFieldName) {
+        if (endpointType == SparqlEndpointTypeEnum.ARQ || endpointType == SparqlEndpointTypeEnum.LARQ) {
+            queryString.append(String.format("  { \n    ?incoming ?p ?%s . \n  } \n", rootFieldName));
+        } // else ... for Virtuoso we need not count incoming links, because it
+          // has a
+          // page rank like feature we can use to rank entities!
+          // all others do not support sorting
+    }
+
+    /**
+     * @param endpointType
+     * @param queryString
+     */
+    private static void addRankingOrder(SparqlEndpointTypeEnum endpointType,
+                                        final StringBuilder queryString,
+                                        String rootVarName,
+                                        String intend) {
+        if (endpointType == SparqlEndpointTypeEnum.Virtuoso) {
+            // is that still SPARQL ... wondering about the syntax ^
+            queryString.append(String.format("%sORDER BY DESC ( <LONG::IRI_RANK> (?%s) ) \n",
+                intend != null ? intend : "", rootVarName));
+        } else if (endpointType == SparqlEndpointTypeEnum.ARQ || endpointType == SparqlEndpointTypeEnum.LARQ) {
+            // TODO: COUNT is not part of the SPARQL 1.0 specification!
+            // see http://www.w3.org/2009/sparql/wiki/Feature:AggregateFunctions
+            queryString.append(String.format("%sORDER BY DESC (COUNT (?incoming) ) \n",
+                intend != null ? intend : ""));
+        } // else not supported ... add nothing
+    }
+
+    /**
+     * @param query
+     * @param queryString
+     */
+    private static void addOffset(SparqlFieldQuery query, final StringBuilder queryString) {
+        if (query.getOffset() > 0) {
+            queryString.append(String.format("OFFSET %d \n", query.getOffset()));
+        }
+    }
+
+    /**
+     * @param query
+     * @param queryString
+     */
+    private static void addLimit(Integer limit, final StringBuilder queryString) {
+        if (limit != null && limit > 0) {
+            queryString.append(String.format("LIMIT %d \n", limit));
+        }
+    }
+
+    /**
+     * Adds the SELECT part to the SPARQL query
+     * 
+     * @param queryString
+     * @param query
+     * @param includeFields
+     * @param selectedFields
+     */
+    private static void createSelect(final StringBuilder queryString,
+                                     boolean includeFields,
+                                     final Map<String,String> selectedFields) {
+        queryString.append("SELECT DISTINCT");
+        // REMOVED: The root variable is already in the selected fields map!
+        // queryString.append(" ?"+query.getRootVariableName()); //select the
+        // representation ID
+
+        // now the variables for the selected fields!
+        if (includeFields) {
+            for (String varName : selectedFields.values()) {
+                queryString.append(" ?");
+                queryString.append(varName);
+            }
+        } else {
+            // else add only the root variable (stored under key null)
+            queryString.append(" ?");
+            queryString.append(selectedFields.get(null));
+        }
+        queryString.append(" \n");
+    }
+
+    /**
+     * Adds the WHERE clause of the SPARQL query.
+     * <p>
+     * If the {@link SparqlEndpointTypeEnum SPARQL endpoint} supports SPARQL 1.1 subqueries, than this adds also the
+     * LIMIT and OFFSET to in inner SELECT that only selects the id.
+     * 
+     * @param queryString
+     *            the SPARQL query string to add the WHERE
+     * @param query
+     *            the query
+     * @param selectedFields
+     *            the selected fields
+     * @param endpointType
+     *            The type of the endpoint (used to write optimised queries for endpoint type specific
+     *            extensions
+     */
+    private static void addFieldConstraint(final StringBuilder queryString,
+                                           SparqlFieldQuery query,
+                                           Map<String,String> selectedFields,
+                                           SparqlEndpointTypeEnum endpointType) {
+        // we need temporary variables with unique names
+        String varPrefix = "tmp";
+        int[] varNum = new int[] {1};
+        // used to open brackets for the select part of the constraints
+        boolean first = true;
+        // determine if sub-selects are supported and if we need a sub-select
+        // (more than the id is selected)
+        boolean subSelectState = isSubSelectState(endpointType, selectedFields);
+
+        log.trace("add field constraints is in a sub-select-state [{}].", (subSelectState ? "yes" : "no"));
+        // if we uses a sub query to select the ids, we need to add the graph
+        // pattern
+        // of all selected fields outside of the sub query
+        Map<String,String> tmpSelectedFields = subSelectState ? new HashMap<String,String>(selectedFields)
+                : null;
+        String intend;
+        if (subSelectState) {
+            intend = "      "; // additional intend because of sub query (3*2)
+        } else {
+            intend = "    "; // normal intend (2*2)
+        }
+        Iterator<Entry<String,Constraint>> constraintIterator = query.iterator();
+        while (constraintIterator.hasNext()) {
+            Entry<String,Constraint> fieldConstraint = constraintIterator.next();
+            // for (Entry<String, Constraint> fieldConstraint : query) {
+
+            if (first) {
+                queryString.append("  { \n");
+                if (subSelectState) {
+                    String rootVarName = selectedFields.get(null);
+                    queryString.append("    SELECT ?").append(rootVarName).append(" \n");
+                    queryString.append("    WHERE { \n");
+                }
+                first = false;
+            }
+            String field = fieldConstraint.getKey();
+            Constraint constraint = fieldConstraint.getValue();
+
+            log.trace("adding a constraint [type :: {}][field :: {}][prefix :: {}][intent :: {}].",
+                new Object[]{constraint.getType(), field, varPrefix, intend});
+
+            switch (constraint.getType()) {
+                case value:
+                    addValueConstraint(queryString, field, (ValueConstraint) constraint, selectedFields,
+                        varPrefix, varNum, intend);
+                    break;
+                case text:
+                    String var = addFieldGraphPattern(queryString, field, selectedFields, varPrefix, varNum,
+                        intend);
+                    addTextConstraint(queryString, var, (TextConstraint) constraint, endpointType, intend);
+                    break;
+                case range:
+                    var = addFieldGraphPattern(queryString, field, selectedFields, varPrefix, varNum, intend);
+                    addRangeConstriant(queryString, var, (RangeConstraint) constraint, intend);
+                    break;
+                default:
+                    log.warn("Please update this Implementation to support the Constraint Type "
+                             + fieldConstraint.getValue().getType());
+                    break;
+            }
+
+            queryString.append(" . \n");
+        }
+        // for some endpoints we need to add an additional constraints used for
+        // ranking. If sub-queries are used this need to be in the select part
+        // of the query (to rank results of the inner query)
+        // otherwise it is better to have it in outside if the select part to
+        // only
+        // rank the graph selected by the query
+        if (subSelectState) {
+            addRankingConstraints(endpointType, queryString, selectedFields.get(null));
+        }
+        if (!first) {
+            if (subSelectState) {
+                queryString.append("    } \n");
+                // re-add all selected fields to be added as selects because in
+                // the sub-query we only select the ID!
+                selectedFields = tmpSelectedFields;
+                // ranking needs also to be added to the sub-query (to correctly
+                // process LIMIT and OFFSET
+                addRankingOrder(endpointType, queryString, selectedFields.get(null), "    ");
+                // add LIMIT and OFFSET to the sub-query!
+                // TODO: add link to the email
+                queryString.append("    ");
+                addLimit(query.getLimit(), queryString);
+                queryString.append("    ");
+                addOffset(query, queryString);
+                queryString.append("    ");
+            }
+            queryString.append("  } \n");
+        }
+        // All the followig Graphpattern are only processed for the parts
+        // selected
+        // by the above constraints
+        // if no subqueries are used we need now to add the ranking constraints
+        if (!subSelectState) {
+            addRankingConstraints(endpointType, queryString, selectedFields.get(null));
+        }
+        // we need to add graph pattern for selected field that are not covered
+        // by
+        // graph pattern written for the constraint.
+        // Implementation Note: selectedFields contains the null key for the
+        // root variable
+        while (selectedFields.size() > 1) { // if this is the only left element
+                                            // we are done
+            Iterator<String> it = selectedFields.keySet().iterator();
+            String actField; // we need to get a non null value from the map
+            do {
+                // the outer while ensures an non null value so we need not to
+                // use hasNext
+                actField = it.next();
+            } while (actField == null);
+            queryString.append("  OPTIONAL { ");
+            // NOTE the following Method removes the written mapping from the
+            // Map
+            addFieldGraphPattern(queryString, actField, selectedFields, varPrefix, varNum, "");
+            queryString.append(". } \n");
+        }
+    }
+
+    private static void addValueConstraint(StringBuilder queryString,
+                                           String field,
+                                           ValueConstraint constraint,
+                                           Map<String,String> selectedFields,
+                                           String varPrefix,
+                                           int[] varNum,
+                                           String intend) {
+        String rootVarName = selectedFields.get(null);
+        Collection<String> dataTypes = constraint.getDataTypes();
+        if (dataTypes == null) {
+            // we need not to distinguish between empty and null
+            // because SPARQL includes support for automatic detection of
+            // dataTypes
+            // see http://www.w3.org/TR/rdf-sparql-query/#QSynLiterals
+            dataTypes = Collections.emptySet();
+        }
+        if (constraint.getValues() != null) {
+            if (dataTypes.size() <= 1) {
+                addDataTypeValueConstraint(queryString, rootVarName, field, dataTypes.isEmpty() ? null
+                        : dataTypes.iterator().next(), constraint.getValues(), constraint.getMode(),
+                    varPrefix, varNum, intend);
+            } else { // we have multiple dataTypes -> need to use union!
+                boolean first = true;
+                for (Iterator<String> it = dataTypes.iterator(); it.hasNext();) {
+                    String dataType = it.next();
+                    if (first) {
+                        queryString.append('{');
+                        first = false;
+                    } else {
+                        queryString.append("} UNION {\n");
+                    }
+                    addDataTypeValueConstraint(queryString, rootVarName, field, dataType,
+                        constraint.getValues(), constraint.getMode(), varPrefix, varNum, intend);
+                }
+                queryString.append('}');
+            }
+        } else { // no constraint for the value
+            // filter all instances that define any value for the given
+            // dataTypes
+            // see http://www.w3.org/TR/rdf-sparql-query/#func-datatype
+            // first we need to select the Variable to filter
+            String var = addFieldGraphPattern(queryString, field, selectedFields, varPrefix, varNum, intend);
+            queryString.append(". \n").append(intend);
+            // now we need to write the filter
+            if (dataTypes.size() == 1) {
+                addDataTypeFilter(queryString, var, dataTypes.iterator().next());
+            } else {
+                boolean first = true;
+                for (Iterator<String> it = dataTypes.iterator(); it.hasNext();) {
+                    String dataType = it.next();
+                    if (first) {
+                        queryString.append("( \n  ").append(intend);
+                        first = false;
+                    } else {
+                        queryString.append(" || \n  ").append(intend);
+                    }
+                    addDataTypeFilter(queryString, var, dataType);
+                }
+                queryString.append(" \n").append(intend).append(")");
+            }
+        }
+    }
+
+    /**
+     * Adds a filter that restricts the data type to an variable
+     * 
+     * @param queryString
+     *            the query String to add the filter. MUST NOT be <code>null</code>
+     * @param var
+     *            the variable to add the filter. MUST NOT be <code>null</code>
+     * @param dataTypes
+     *            the data type uri for the filter. MUST NOT be <code>null</code>
+     */
+    private static void addDataTypeFilter(StringBuilder queryString, String var, String dataType) {
+        queryString.append(String.format("FILTER(datatype(?%s) = <%s>)", var, dataType));
+    }
+
+    /**
+     * Adds a value constraint for a field including the dataType
+     * 
+     * @param queryString
+     *            the query string to add the constraint. MUST NOT be <code>null</code>
+     * @param rootVarName
+     *            the variable name of the subject. MUST NOT be <code>null</code>
+     * @param field
+     *            the property name of the field. MUST NOT be <code>null</code>
+     * @param dataType
+     *            the dataType constraint or <code>null</code> if none
+     * @param value
+     *            the value. MUST NOT be <code>null</code>.
+     */
+    private static void addDataTypeValueConstraint(StringBuilder queryString,
+                                                   String rootVarName,
+                                                   String field,
+                                                   String dataType,
+                                                   Collection<Object> values,
+                                                   MODE mode,
+                                                   String varPrefix,
+                                                   int[] varNum,
+                                                   String intend) {
+        String addIntend = intend;
+        queryString.append(intend);
+        if (values.size() > 1) {
+            queryString.append("{ ");
+            addIntend = intend + "  ";
+        }
+        boolean first = true;
+        for (Object value : values) {
+            if (first) {
+                // only add bracket if multiple values are parsed (STANBOL-697)
+                if (mode == MODE.any && values.size() > 1) {
+                    queryString.append('{');
+                }
+                first = false;
+            } else {
+                if (mode == MODE.any) {
+                    queryString.append("} UNION {\n");
+                } else {
+                    queryString.append(" .\n");
+                }
+                queryString.append(addIntend);
+            }
+            String fieldVar;
+            if (isSpecialField(field)) {
+                // in case of a special field replace the field URI with an
+                // variable to allow searching all outgoing properties
+                fieldVar = varPrefix + varNum[0];
+                varNum[0]++;
+            } else {
+                fieldVar = null;
+            }
+            if (DataTypeEnum.Reference.getUri().equals(dataType) || value instanceof Reference) {
+                if (fieldVar != null) {
+                    queryString.append(String.format("?%s ?%s <%s>", rootVarName, fieldVar, value));
+                } else {
+                    queryString.append(String.format("?%s <%s> <%s>", rootVarName, field, value));
+                }
+            } else {
+                if (fieldVar != null) {
+                    queryString.append(String.format("?%s ?%s \"%s\"%s", rootVarName, 
+                        getGrammarEscapedValue(fieldVar), value,
+                        dataType != null ? String.format("^^<%s>", dataType) : ""));
+                } else {
+                    queryString.append(String.format("?%s <%s> \"%s\"%s", rootVarName, field, value,
+                        dataType != null ? String.format("^^<%s>", dataType) : ""));
+                }
+            }
+        }
+        if (values.size() > 1) {
+            if (mode == MODE.any) { // close the union
+                queryString.append('}');
+            }
+            queryString.append(" }");
+        }
+    }
+
+    /**
+     * Adds an text constraint to the SPARQL query string
+     * 
+     * @param queryString
+     *            the query string to add the constraint
+     * @param var
+     *            the variable name to constraint
+     * @param constraint
+     *            the constraint
+     * @param endpointType
+     *            The type of the Endpoint (used to write optimized queries for endpoint type specific
+     *            extensions
+     */
+    private static void addTextConstraint(StringBuilder queryString,
+                                          String var,
+                                          TextConstraint constraint,
+                                          SparqlEndpointTypeEnum endpointType,
+                                          String intend) {
+        boolean filterAdded = false;
+        boolean isTextValueConstraint = constraint.getTexts() != null && !constraint.getTexts().isEmpty();
+
+        log.trace("Constraint is text-value constrain [{}][var :: {}][intent :: {}].",
+            new Object[]{(isTextValueConstraint ? "yes" : "no"), var, intend});
+
+        if (isTextValueConstraint) {
+
+            if (constraint.getPatternType() == PatternType.regex) {
+                queryString.append(" \n").append(intend).append("  FILTER(");
+                filterAdded = true;
+                addRegexFilter(queryString, var, constraint.getTexts(), constraint.isCaseSensitive());
+            } else {
+                // TODO: This optimised versions for Virtuoso and LARQ might not
+                // respect case sensitive queries. Need more testing!
+                if (SparqlEndpointTypeEnum.Virtuoso == endpointType) {
+                    queryString.append(". \n  ").append(intend);
+                    queryString.append(String.format("?%s bif:contains '%s'", var,
+                        createFullTextQueryString(constraint.getTexts())));
+                } else if (SparqlEndpointTypeEnum.LARQ == endpointType) {
+                    queryString.append(". \n  ").append(intend);
+                    queryString.append(String.format(
+                        "?%s <http://jena.hpl.hp.com/ARQ/property#textMatch> '%s'", var,
+                        createFullTextQueryString(constraint.getTexts())));
+                } else {
+                    queryString.append(" \n").append(intend).append("  FILTER(");
+                    filterAdded = true;
+                    if (constraint.getPatternType() == PatternType.none) {
+                        if (constraint.isCaseSensitive()) {
+                            boolean first = true;
+                            for (String textConstraint : constraint.getTexts()) {
+                                if (first) {
+                                    first = false;
+                                } else {
+                                    queryString.append(" || ");
+                                }
+                                if (textConstraint != null && !textConstraint.isEmpty()) {
+                                    queryString.append("(str(").append(var).append(") = \"");
+                                    addGrammarEscapedValue(queryString, textConstraint);
+                                    queryString.append("\")");
+                                }
+                            }
+                        } else {
+                            Collection<String> regexQueryTexts = new ArrayList<String>(
+                                    constraint.getTexts().size());
+                            for (String textConstraint : constraint.getTexts()) {
+                                if (textConstraint != null && !textConstraint.isEmpty()) {
+                                    regexQueryTexts.add(PatternUtils.value2Regex(textConstraint));
+                                }
+                            }
+                            addRegexFilter(queryString, var, regexQueryTexts, constraint.isCaseSensitive());
+                        }
+                    } else if (constraint.getPatternType() == PatternType.wildcard) {
+                        // parse false, because that is more in line with the
+                        // expectations of users!
+                        Collection<String> regexQueryTexts = new ArrayList<String>(constraint.getTexts()
+                                .size());
+                        for (String textConstraint : constraint.getTexts()) {
+                            if (textConstraint != null && !textConstraint.isEmpty()) {
+                                regexQueryTexts.add(PatternUtils.wildcardToRegex(textConstraint, false));
+                            }
+                        }
+                        addRegexFilter(queryString, var, regexQueryTexts, constraint.isCaseSensitive());
+                    } else {
+                        log.warn("Unspported Patterntype "
+                                 + constraint.getPatternType()
+                                 + "! Change this impplementation to support this type! -> treat constaint \""
+                                 + constraint.getTexts() + "\"as REGEX");
+                        addRegexFilter(queryString, var, constraint.getTexts(), constraint.isCaseSensitive());
+                    }
+                }
+            }
+        } // else nothing to do add language Filters
+        // TODO check if FILTER ( is already written!
+        if (constraint.getLanguages() != null && !constraint.getLanguages().isEmpty()) {
+
+            log.trace("Constraint has languages [filter-added :: {}].", 
+                (filterAdded ? "yes" : "no"));
+
+            if (!filterAdded) {
+                queryString.append(" . \n").append(intend).append("  FILTER(");
+                filterAdded = true;
+                writeLanguagesFilter(queryString, constraint.getLanguages(), var, null);
+            } else {
+                writeLanguagesFilter(queryString, constraint.getLanguages(), var, " && ");
+            }
+        }
+        if (filterAdded) {
+            queryString.append(")"); // close the FILTER and the graph pattern
+        }
+    }
+
+    /**
+     * (Creates AND Text) OR (Query AND String) like queries based on the parsed TextConstraint as used by
+     * {@link SparqlEndpointTypeEnum#LARQ LARQ} and {@link SparqlEndpointTypeEnum#Virtuoso VIRTUOSO} SPARQL endpoints to
+     * speed up full text queries.
+     * 
+     * @param constraints
+     *            the as returned by {@link TextConstraint#getTexts()}
+     * @return the full text query string
+     */
+    protected static String createFullTextQueryString(Collection<String> constraints) {
+        StringBuilder textQuery = new StringBuilder();
+        boolean firstText = true;
+        for (String constraintText : constraints) {
+            if (constraintText != null && !constraintText.isEmpty()) {
+                if (firstText) {
+                    firstText = false;
+                } else {
+                    textQuery.append(" OR ");
+                }
+                // TODO: maybe we should use a word tokenizer here
+                String[] words = constraintText.split("\\s");
+                if (words.length > 1) {
+                    // not perfect because words might contain empty string, but
+                    // it will eliminate most unnecessary brackets .
+                    textQuery.append('(');
+                }
+                boolean firstAndWord = true;
+                for (String word : words) {
+                    word = word.trim();
+                    boolean hasAlphaNumeric = false;
+                    for (int i = 0; i < word.length() && !hasAlphaNumeric; i++) {
+                        char ch = word.charAt(i);
+                        if (Character.isLetter(ch) || Character.isDigit(ch)) {
+                            hasAlphaNumeric = true;
+                        }
+                    }
+                    if (hasAlphaNumeric) {
+                        if (firstAndWord) {
+                            firstAndWord = false;
+                        } else {
+                            textQuery.append(" AND ");
+                        }
+
+                        textQuery.append('"');
+                        addGrammarEscapedValue(textQuery, word);
+                        textQuery.append('"');
+                    }
+                }
+                if (words.length > 1) {
+                    textQuery.append(')');
+                }
+            } // end if not null and not empty
+        }
+        return textQuery.toString();
+    }
+    /**
+     * Version of {@link #addGrammarEscapedValue(StringBuilder, String)} that
+     * returns the escapedValue
+     * @param value
+     * @return
+     * @see #addGrammarEscapedValue(StringBuilder, String)
+     */
+    protected static final String getGrammarEscapedValue(String value){
+        StringBuilder sb = new StringBuilder(value.length()+4);
+        addGrammarEscapedValue(sb, value);
+        return sb.toString();
+    }
+    /**
+     * Encode Strings as specified in the SPARQL specification section
+     * <a href="http://www.w3.org/TR/rdf-sparql-query/#grammarEscapes"> 
+     * A.7 Escape sequences in strings</a>
+     * @param query
+     * @param value
+     */
+    private static final void addGrammarEscapedValue(StringBuilder query, String value){
+        for(int i=0;i<value.length();i++){
+            switch (value.charAt(i)) {
+                case '\t': case '\n': case '\r': case '\b': case '\f':
+                case '"': case '\'': case '\\': 
+                    query.append('\\');
+            }
+            query.append(value.charAt(i));
+        }
+    }
+
+    /**
+     * Adds a SPARQL regex filter to the parsed query string
+     * 
+     * @param queryString
+     *            the string builder to add the constraint
+     * @param var
+     *            the variable to constrain
+     * @param regexContraints
+     *            the regex encoded search strings (connected with '||' (OR))
+     * @param isCasesensitive
+     *            if the constraint is case sensitive or not
+     */
+    private static void addRegexFilter(StringBuilder queryString,
+                                       String var,
+                                       Collection<String> regexContraints,
+                                       boolean isCasesensitive) {
+        boolean first = true;
+        for (String regex : regexContraints) {
+            if (regex != null && !regex.isEmpty()) {
+                if (first) {
+                    first = false;
+                } else {
+                    queryString.append(" || ");
+                }
+                queryString.append("regex(str(").append(var).append(",\"");
+                addGrammarEscapedValue(queryString, regex);
+                queryString.append('\"');
+                if(!isCasesensitive){
+                    queryString.append(",\"i\"");
+                }
+                queryString.append(')');
+            }
+        }
+    }
+
+    /**
+     * Adds an RangeConstraint to the parsed query String
+     * 
+     * @param queryString
+     *            the query to add the constraint
+     * @param var
+     *            the variable to constrain
+     * @param constraint
+     *            the constraint
+     */
+    private static void addRangeConstriant(StringBuilder queryString,
+                                           String var,
+                                           RangeConstraint constraint,
+                                           String intend) {
+        queryString.append("\n").append(intend).append("FILTER "); // start the
+                                                                   // FILTER
+        boolean closedRange = constraint.getLowerBound() != null && constraint.getUpperBound() != null;
+        if (closedRange) {
+            queryString.append("(");
+        }
+        // write lower and upper bounds
+        if (constraint.getLowerBound() != null) {
+            addRangeBound(queryString, var, true, constraint.isInclusive(), constraint.getLowerBound());
+        }
+        if (closedRange) {
+            queryString.append(" && ");
+        }
+        if (constraint.getUpperBound() != null) {
+            addRangeBound(queryString, var, false, constraint.isInclusive(), constraint.getUpperBound());
+        }
+        if (closedRange) {
+            queryString.append(")");
+        }
+    }
+
+    /**
+     * Adds a lower/upper bound constraint to the query String
+     * 
+     * @param queryString
+     *            the query string
+     * @param var
+     *            the variable
+     * @param lowerBound
+     *            <code>true</code> to add the lower bound and <code>false</code> to add the upper bound
+     * @param inclusive
+     *            if the bound is inclusive (>= or <=)
+     * @param value
+     *            the value representing the bound.
+     */
+    private static void addRangeBound(StringBuilder queryString,
+                                      String var,
+                                      boolean lowerBound,
+                                      boolean inclusive,
+                                      Object value) {
+        String stringValue;
+        if (value instanceof Date) {// for dates add the data type!
+            stringValue = String.format("%s^^<%s>", TimeUtils.toString(DataTypeEnum.DateTime, (Date)value), XSD_DATE_TIME);
+        } else { // add additional "if" for special types if necessary
+            stringValue = value.toString();
+        }
+        // adds (?var >/<[=] valueString)
+        queryString.append(String.format("(?%s %c%s %s)", var, lowerBound ? '>' : '<', inclusive ? "=" : "",
+            stringValue));
+    }
+
+    /**
+     * Adds a S P O pattern to the query by using the root as subject, the parsed field as predicate and the
+     * returned variable as object. This method doese not open a '{' nor close the pattern with any of '.',
+     * ',' or ';'
+     * 
+     * @param queryString
+     *            the {@link StringBuilder} to add the pattern
+     * @param field
+     *            the field
+     * @param selectedFields
+     *            the map field -> var of the selected variables. If the parsed field is selected, the field
+     *            is removed from the list and the mapped variable name is returned
+     * @param varPrefix
+     *            the default prefix for newly created variable names
+     * @param varNum
+     *            The first element of the array is used to get the number of the created variable. If one is
+     *            created the value of the first element is increased by one
+     * @return The variable name used for the object of the pattern
+     */
+    private static String addFieldGraphPattern(StringBuilder queryString,
+                                               String field,
+                                               Map<String,String> selectedFields,
+                                               String varPrefix,
+                                               int[] varNum,
+                                               String intend) {
+        String var = selectedFields.remove(field); // check if the field is
+                                                   // selected
+        if (var == null) { // this field is not selected
+            // we need to generate a temp var
+            var = varPrefix + varNum[0];
+            varNum[0]++;
+        }
+        if (isSpecialField(field)) {
+            // in case of a special field replace the field URI with an
+            // variable to allow searching all outgoing properties
+            String fieldVar = varPrefix + varNum[0];
+            varNum[0]++;
+            queryString.append(String.format("%s?%s ?%s ?%s ", intend, selectedFields.get(null), fieldVar,
+                var));
+        } else {
+            queryString
+                    .append(String.format("%s?%s <%s> ?%s ", intend, selectedFields.get(null), field, var));
+        }
+        return var;
+    }
+
+    /**
+     * Writes the SPARQL FILTER for the parsed languages. This Method writes <code><pre>
+     *      prefix ((lang(?var) = "lang1") [|| (lang(?var) = "lang2..n")])
+     * </pre></code>
+     * 
+     * @param queryString
+     *            the query string to add the FILTER
+     * @param languages
+     *            the languages to filter for (may contain <code>null</code> as element)
+     * @param var
+     *            the name of the variable to filter.
+     * @param prefix
+     *            The prefix is written in front of the filter expression (if any is created). Typically this
+     *            will be
+     *            <ul>
+     *            <li>FILTER if this is the only filter for an variable
+     *            <li>&& if this filter is combined with AND to an other filter or
+     *            <li>|| if this filter is combined wit OR to an other filter
+     *            </ul>
+     */
+    private static void writeLanguagesFilter(StringBuilder queryString,
+                                             Collection<String> languages,
+                                             String var,
+                                             String prefix) {
+
+        if (null == languages || languages.isEmpty()) return;
+
+        log.trace("Writing languages filter [var :: {}][prefix :: {}][languages :: {}].", 
+            new Object[]{var, prefix, languages.size()});
+
+        if (prefix != null) {
+            queryString.append(prefix);
+        }
+        if (languages.size() > 1) {
+            queryString.append("(");
+        }
+        boolean first = true;
+        for (String language : languages) {
+            if (first) {
+                first = false;
+            } else {
+                queryString.append(" || ");
+            }
+            queryString.append(String.format("(lang(?%s) = \"%s\")", var, language != null ? language : ""));
+            /*
+             * NOTE: the lang() returns "" for literals without an language tag. Because of that if the
+             * language == null we need to parse "" as an argument
+             */
+        }
+        if (languages.size() > 1) {
+            queryString.append(")");
+        }
+    }
+
+    public static void main(String[] args) {
+        SparqlFieldQuery query = SparqlFieldQueryFactory.getInstance().createFieldQuery();
+        // query.setConstraint("urn:field1", new
+        // ReferenceConstraint("urn:testReference"));
+        // query.setConstraint("urn:field1", new ReferenceConstraint(
+        // Arrays.asList("urn:testReference","urn:testReference1","urn:testReference3"),MODE.any));
+        // query.setConstraint(SpecialFieldEnum.references.getUri(), new
+        // ReferenceConstraint(
+        // Arrays.asList("urn:testReference","urn:testReference1","urn:testReference3")));
+        // query.setConstraint("urn:field1a", new ValueConstraint(null,
+        // Arrays.asList(
+        // DataTypeEnum.Float.getUri())));
+        // query.addSelectedField("urn:field1a");
+
+        // query.setConstraint("urn:field1b", new ValueConstraint(9, Arrays.asList(
+        // DataTypeEnum.Float.getUri())));
+        // query.setConstraint("urn:field1b", new ValueConstraint(Arrays.asList(9,10,11), Arrays.asList(
+        // DataTypeEnum.Float.getUri()),MODE.any));
+        // query.setConstraint("urn:field1c", new ValueConstraint(null, Arrays.asList(
+        // DataTypeEnum.Float.getUri(),DataTypeEnum.Double.getUri(),DataTypeEnum.Decimal.getUri())));
+        // query.addSelectedField("urn:field1c");
+        // query.setConstraint("urn:field1d", new ValueConstraint(9, Arrays.asList(
+        // DataTypeEnum.Float.getUri(),DataTypeEnum.Double.getUri(),DataTypeEnum.Decimal.getUri())));
+        // query.setConstraint("urn:field1d", new ValueConstraint(Arrays.asList(9,10,11), Arrays.asList(
+        // DataTypeEnum.Float.getUri(),DataTypeEnum.Double.getUri(),DataTypeEnum.Decimal.getUri())));
+        // query.setConstraint("urn:field2", new TextConstraint("test value"));
+        // query.setConstraint("urn:field3", new TextConstraint(Arrays.asList(
+        // "text value","anothertest","some more values"),true));
+        // query.setConstraint(SpecialFieldEnum.fullText.getUri(), new TextConstraint(Arrays.asList(
+        // "text value","anothertest","some more values"),true));
+        // query.setConstraint("urn:field2a", new TextConstraint(":-]"));
+        // //tests escaping of REGEX
+        // query.setConstraint("urn:field3", new TextConstraint("language text","en"));
+        query.setConstraint("urn:field4", new TextConstraint("multi language text", "en", "de", null));
+        // query.setConstraint("urn:field5", new
+        // TextConstraint("wildcar*",PatternType.wildcard,false,"en","de"));
+        // query.addSelectedField("urn:field5");
+        // query.setConstraint("urn:field6", new TextConstraint("^regex",PatternType.REGEX,true));
+        // query.setConstraint("urn:field7", new
+        // TextConstraint("par*",PatternType.WildCard,false,"en","de",null));
+        // query.setConstraint("urn:field8", new TextConstraint(null,"en","de",null));
+        // query.setConstraint("urn:field9", new RangeConstraint((int)5, (int)10, true));
+        // query.setConstraint("urn:field10", new RangeConstraint((int)5, (int)10, false));
+        // query.setConstraint("urn:field11", new RangeConstraint(null, (int)10, true));
+        // query.setConstraint("urn:field12", new RangeConstraint((int)5, null, true));
+        query.setConstraint("urn:field12", new RangeConstraint(new Date(), null, true));
+        // query.addSelectedField("urn:field2a");
+        // query.addSelectedField("urn:field3");
+        query.setLimit(5);
+        query.setOffset(5);
+        System.out.println(createSparqlSelectQuery(query, true, 0, SparqlEndpointTypeEnum.LARQ));
+        System.out.println();
+        System.out.println(createSparqlSelectQuery(query, true, 0, SparqlEndpointTypeEnum.Virtuoso));
+        System.out.println();
+        System.out.println(createSparqlSelectQuery(query, true, 0, SparqlEndpointTypeEnum.Standard));
+        System.out.println();
+        System.out.println(createSparqlConstructQuery(query, 0, SparqlEndpointTypeEnum.Virtuoso));
+    }
+}

Added: stanbol/trunk/entityhub/query/sparql/src/test/java/org/apache/stanbol/entityhub/query/sparql/SparqlQueryUtilsTest.java
URL: http://svn.apache.org/viewvc/stanbol/trunk/entityhub/query/sparql/src/test/java/org/apache/stanbol/entityhub/query/sparql/SparqlQueryUtilsTest.java?rev=1531896&view=auto
==============================================================================
--- stanbol/trunk/entityhub/query/sparql/src/test/java/org/apache/stanbol/entityhub/query/sparql/SparqlQueryUtilsTest.java (added)
+++ stanbol/trunk/entityhub/query/sparql/src/test/java/org/apache/stanbol/entityhub/query/sparql/SparqlQueryUtilsTest.java Mon Oct 14 13:47:28 2013
@@ -0,0 +1,109 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You 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 org.apache.stanbol.entityhub.query.sparql;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.stanbol.entityhub.core.query.DefaultQueryFactory;
+import org.apache.stanbol.entityhub.query.sparql.SparqlFieldQuery;
+import org.apache.stanbol.entityhub.query.sparql.SparqlFieldQueryFactory;
+import org.apache.stanbol.entityhub.query.sparql.SparqlQueryUtils;
+import org.apache.stanbol.entityhub.servicesapi.defaults.NamespaceEnum;
+import org.apache.stanbol.entityhub.servicesapi.query.FieldQuery;
+import org.apache.stanbol.entityhub.servicesapi.query.FieldQueryFactory;
+import org.apache.stanbol.entityhub.servicesapi.query.TextConstraint;
+import org.apache.stanbol.entityhub.servicesapi.query.TextConstraint.PatternType;
+import org.junit.Test;
+
+public class SparqlQueryUtilsTest {
+
+    @Test
+    public void testCreateFullTextQueryString() {
+        List<String> keywords = Arrays.asList("test", "keyword");
+        assertEquals("\"test\" OR \"keyword\"", 
+            SparqlQueryUtils.createFullTextQueryString(keywords));
+
+        keywords = Arrays.asList("test keyword");
+        assertEquals("(\"test\" AND \"keyword\")", 
+            SparqlQueryUtils.createFullTextQueryString(keywords));
+
+        keywords = Arrays.asList("'test' \"keyword\"");
+        assertEquals("(\"\\'test\\'\" AND \"\\\"keyword\\\"\")",
+            SparqlQueryUtils.createFullTextQueryString(keywords));
+        
+        keywords = Arrays.asList("1 Alpha ? Numeric Test .");
+        assertEquals("(\"1\" AND \"Alpha\" AND \"Numeric\" AND \"Test\")",
+            SparqlQueryUtils.createFullTextQueryString(keywords));
+        
+    }
+    /**
+     * Tests for grammar encoding (STANBOL-877)
+     */
+    @Test
+    public void testGrammarEncodning(){
+        assertEquals("test\\'s",SparqlQueryUtils.getGrammarEscapedValue("test's")); 
+        assertEquals("test\\\"s",SparqlQueryUtils.getGrammarEscapedValue("test\"s")); 
+        assertEquals("new\\\nline",SparqlQueryUtils.getGrammarEscapedValue("new\nline")); 
+        
+    }
+    
+    /**
+     * Utility function for generating SparqlQuery
+     * @param textWithDoubleQuote
+     * @param patternType
+     */
+    private String generateSparqlQueryString(String textWithDoubleQuote, PatternType patternType) {
+    	int limit = 10;
+    	FieldQueryFactory qf = DefaultQueryFactory.getInstance();
+    	FieldQuery query = qf.createFieldQuery();
+      
+    	String DEFAULT_AUTOCOMPLETE_SEARCH_FIELD = NamespaceEnum.rdfs+"label";
+      
+    	Collection<String> selectedFields = new ArrayList<String>();
+    	selectedFields.add(DEFAULT_AUTOCOMPLETE_SEARCH_FIELD);
+    	query.addSelectedFields(selectedFields);
+    	query.setConstraint(DEFAULT_AUTOCOMPLETE_SEARCH_FIELD, 
+      		new TextConstraint(textWithDoubleQuote, patternType, true, "en",null));
+    	query.setLimit(10);
+    	query.setOffset(0);
+    	
+    	final SparqlFieldQuery sparqlQuery = SparqlFieldQueryFactory.getSparqlFieldQuery(query);
+    	
+    	return SparqlQueryUtils.createSparqlSelectQuery(sparqlQuery, false,limit,SparqlEndpointTypeEnum.Standard);
+	}
+    
+    @Test
+    public void testDoubleQuotes(){
+    	String testString = "double\"quote";
+    	
+    	String queryNone = generateSparqlQueryString(testString,PatternType.none);
+    	//the quote have to be double escaped before checked with .contains
+    	assertTrue(queryNone.contains(testString.replaceAll("\\\"", "\\\\\"")));
+    	
+    	String queryRegex = generateSparqlQueryString(testString,PatternType.regex);
+    	assertTrue(queryRegex.contains(testString.replaceAll("\\\"", "\\\\\"")));
+    }
+
+	
+
+}