allowing queries with bnodes
diff --git a/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlBNode.java b/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlBNode.java
index c74aa06..f55f7af 100644
--- a/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlBNode.java
+++ b/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlBNode.java
@@ -32,7 +32,7 @@
  */
 class SparqlBNode extends BlankNode {
     
-    private final static Iri internalBNodeId = new Iri("urn:x-internalid:fdmpoihdfw");
+    final static Iri internalBNodeId = new Iri("urn:x-internalid:fdmpoihdfw");
     
     final ImmutableGraph context;
     private final int isoDistinguisher;
diff --git a/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlClient.java b/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlClient.java
index ca3f619..e522924 100644
--- a/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlClient.java
+++ b/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlClient.java
@@ -1,21 +1,26 @@
 /*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
+ * Copyright 2015 The Apache Software Foundation.
+ *
+ * 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 org.apache.commons.rdf.impl.sparql;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
-import java.util.Enumeration;
 import java.util.HashMap;
-import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 import org.apache.http.HttpEntity;
 import org.apache.http.NameValuePair;
 import org.apache.http.client.entity.UrlEncodedFormEntity;
@@ -27,12 +32,9 @@
 import org.apache.http.util.EntityUtils;
 import javax.xml.parsers.*;
 import org.apache.commons.rdf.BlankNode;
-import org.apache.commons.rdf.BlankNodeOrIri;
 import org.apache.commons.rdf.Iri;
 import org.apache.commons.rdf.Language;
-import org.apache.commons.rdf.Literal;
 import org.apache.commons.rdf.RdfTerm;
-import org.apache.commons.rdf.Triple;
 import org.apache.commons.rdf.impl.utils.AbstractLiteral;
 import org.xml.sax.*;
 import org.xml.sax.helpers.*;
diff --git a/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlGraph.java b/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlGraph.java
index 720f7df..7a4c48d 100644
--- a/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlGraph.java
+++ b/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlGraph.java
@@ -26,7 +26,6 @@
 import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.concurrent.Callable;
-import java.util.logging.Level;
 import java.util.logging.Logger;
 import org.apache.commons.rdf.BlankNode;
 import org.apache.commons.rdf.BlankNodeOrIri;
@@ -50,7 +49,6 @@
     private static final Logger log = Logger.getLogger(SparqlGraph.class.getName());
 
     final SparqlClient sparqlClient;
-    
 
     /**
      * Constructs a Graph representing the default graph at the specified
@@ -64,27 +62,8 @@
     protected Iterator<Triple> performFilter(final BlankNodeOrIri filterSubject,
             final Iri filterPredicate, final RdfTerm filterObject) {
         try {
-            final StringBuilder queryBuilder = new StringBuilder();
-            queryBuilder.append("SELECT ?s ?p ?o WHERE { ");
-            if (filterSubject == null) {
-                queryBuilder.append("?s");
-            } else {
-                queryBuilder.append(asSparqlTerm(filterSubject));
-            }
-            queryBuilder.append(' ');
-            if (filterPredicate == null) {
-                queryBuilder.append("?p");
-            } else {
-                queryBuilder.append(asSparqlTerm(filterPredicate));
-            }
-            queryBuilder.append(' ');
-            if (filterObject == null) {
-                queryBuilder.append("?o");
-            } else {
-                queryBuilder.append(asSparqlTerm(filterObject));
-            }
-            queryBuilder.append(" }");
-            final List<Map<String, RdfTerm>> sparqlResults = sparqlClient.queryResultSet(queryBuilder.toString());
+            String query = createQuery(filterSubject, filterPredicate, filterObject);
+            final List<Map<String, RdfTerm>> sparqlResults = sparqlClient.queryResultSet(query);
             //first to triples without bnode-conversion
             //rawTriples contains the triples with the BNodes from the result set
             final Collection<Triple> rawTriples = new ArrayList<>();
@@ -231,57 +210,10 @@
                  * @return
                  */
                 private Set<ImmutableGraph> expandContext(Collection<Triple> startContext) throws IOException {
-                    final Collection<String> triplePatterns = new ArrayList<>();
-                    int varCounter = 0;
-                    final Map<BlankNode, String> bNodeVarNameMap = new HashMap<>();
-                    for (Triple t : startContext) {
-                        final StringBuilder builder = new StringBuilder();
-                        {
-                            final BlankNodeOrIri s = t.getSubject();
-                            String varName;
-                            if (s instanceof BlankNode) {
-                                if (bNodeVarNameMap.containsKey(s)) {
-                                    varName = bNodeVarNameMap.get(s);
-                                } else {
-                                    varName = "v" + (varCounter++);
-                                    bNodeVarNameMap.put((BlankNode) s, varName);
-                                    
-                                }
-                                builder.append('?');
-                                builder.append(varName);
-                            } else {
-                                builder.append(asSparqlTerm(s));
-                            }
-                        }
-                        builder.append(' ');
-                        builder.append(asSparqlTerm(t.getPredicate()));
-                        builder.append(' ');
-                        {
-                            final RdfTerm o = t.getObject();
-                            String varName;
-                            if (o instanceof BlankNode) {
-                                if (bNodeVarNameMap.containsKey(o)) {
-                                    varName = bNodeVarNameMap.get(o);
-                                } else {
-                                    varName = "v" + (varCounter++);
-                                    bNodeVarNameMap.put((BlankNode) o, varName);
-                                }
-                                builder.append('?');
-                                builder.append(varName);
-                            } else {
-                                builder.append(asSparqlTerm(o));
-                            }
-                        }
-                        builder.append('.');
-                        triplePatterns.add(builder.toString());
 
-                    }
                     final StringBuilder queryBuilder = new StringBuilder();
                     queryBuilder.append("SELECT * WHERE {\n ");
-                    for (String triplePattern : triplePatterns) {
-                        queryBuilder.append(triplePattern);
-                        queryBuilder.append('\n');
-                    }
+                    Map<BlankNode, String> bNodeVarNameMap = writeTriplePattern(queryBuilder, startContext);
                     Set<BlankNode> bNodesInContext = bNodeVarNameMap.keySet();
                     for (BlankNode bNode : bNodesInContext) {
                         final String bNodeVarLabel = bNodeVarNameMap.get(bNode);
@@ -404,6 +336,49 @@
         }
     }
 
+    private String createQuery(final BlankNodeOrIri filterSubject, final Iri filterPredicate, final RdfTerm filterObject) {
+        final StringBuilder queryBuilder = new StringBuilder();
+        queryBuilder.append("SELECT ?s ?p ?o WHERE { ");
+        if (filterSubject == null) {
+            queryBuilder.append("?s");
+        } else {
+            if (filterSubject instanceof SparqlBNode) {
+                queryBuilder.append("?sn");
+            } else {
+                queryBuilder.append(asSparqlTerm(filterSubject));
+            }
+        }
+        queryBuilder.append(' ');
+        if (filterPredicate == null) {
+            queryBuilder.append("?p");
+        } else {
+            queryBuilder.append(asSparqlTerm(filterPredicate));
+        }
+        queryBuilder.append(' ');
+        if (filterObject == null) {
+            queryBuilder.append("?o");
+        } else {
+            if (filterObject instanceof SparqlBNode) {
+                queryBuilder.append("?on");
+            } else {
+                queryBuilder.append(asSparqlTerm(filterObject));
+            }
+        }
+        queryBuilder.append(" .\n");
+        if (filterSubject instanceof SparqlBNode) {
+            //expand bnode context
+            writeTriplePattern(queryBuilder, ((SparqlBNode) filterSubject).context, "sn");
+        }
+        
+        if (filterObject instanceof SparqlBNode) {
+            //expand bnode context
+            writeTriplePattern(queryBuilder, ((SparqlBNode) filterObject).context, "on");
+        }
+
+        queryBuilder.append(" }");
+        return queryBuilder.toString();
+    }
+
     @Override
     protected int performSize() {
         try {
@@ -427,7 +402,7 @@
             throw new AlienBNodeException();
         }
         //this requires adding additional clauses to the graph pattern
-        throw new UnsupportedOperationException("Not supported yet.");
+        throw new RuntimeException("SparqlBNodes should have been handled earlier");
     }
 
     private String asSparqlTerm(BlankNodeOrIri term) {
@@ -446,10 +421,80 @@
         }
     }
 
+
+    private Map<BlankNode, String> writeTriplePattern(StringBuilder queryBuilder, Collection<Triple> triples) {
+        return writeTriplePattern(queryBuilder, triples, null);
+    }
+        
+    private Map<BlankNode, String> writeTriplePattern(StringBuilder queryBuilder, Collection<Triple> triples, String varLabelForInternalBNodeId) {
+        final Collection<String> triplePatterns = new ArrayList<>();
+        int varCounter = 0;
+        final Map<BlankNode, String> bNodeVarNameMap = new HashMap<>();
+        for (Triple t : triples) {
+            final StringBuilder builder = new StringBuilder();
+            {
+                final BlankNodeOrIri s = t.getSubject();
+                String varName;
+                if (s instanceof BlankNode) {
+                    if (bNodeVarNameMap.containsKey(s)) {
+                        varName = bNodeVarNameMap.get(s);
+                    } else {
+                        varName = "v" + (varCounter++);
+                        bNodeVarNameMap.put((BlankNode) s, varName);
+                    }
+                    builder.append('?');
+                    builder.append(varName);
+                } else {
+                    if (s.equals(SparqlBNode.internalBNodeId)) {
+                        builder.append('?');
+                        builder.append(varLabelForInternalBNodeId);
+                    } else {
+                        builder.append(asSparqlTerm(s));
+                    }
+                    
+                }
+            }
+            builder.append(' ');
+            builder.append(asSparqlTerm(t.getPredicate()));
+            builder.append(' ');
+            {
+                final RdfTerm o = t.getObject();
+                String varName;
+                if (o instanceof BlankNode) {
+                    if (bNodeVarNameMap.containsKey(o)) {
+                        varName = bNodeVarNameMap.get(o);
+                    } else {
+                        varName = "v" + (varCounter++);
+                        bNodeVarNameMap.put((BlankNode) o, varName);
+                    }
+                    builder.append('?');
+                    builder.append(varName);
+                } else {
+                    if (o.equals(SparqlBNode.internalBNodeId)) {
+                        builder.append('?');
+                        builder.append(varLabelForInternalBNodeId);
+                    } else {
+                        builder.append(asSparqlTerm(o));
+                    }
+                }
+            }
+            builder.append('.');
+            triplePatterns.add(builder.toString());
+
+        }
+        for (String triplePattern : triplePatterns) {
+
+            queryBuilder.append(triplePattern);
+            queryBuilder.append('\n');
+        }
+        return bNodeVarNameMap;
+
+    }
+
     private static class AlienBNodeException extends RuntimeException {
 
         public AlienBNodeException() {
         }
     }
 
-}
\ No newline at end of file
+}
diff --git a/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/BNodeCircleTest.java b/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/BNodeCircleTest.java
index 5208d34..9329c9b 100644
--- a/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/BNodeCircleTest.java
+++ b/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/BNodeCircleTest.java
@@ -1,35 +1,38 @@
 /*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
+ * Copyright 2015 The Apache Software Foundation.
+ *
+ * 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 org.apache.commons.rdf.impl.sparql;
 
 import com.hp.hpl.jena.query.DatasetAccessor;
 import com.hp.hpl.jena.query.DatasetAccessorFactory;
-import java.io.File;
 import java.io.IOException;
 import java.net.ServerSocket;
 import org.apache.jena.fuseki.EmbeddedFusekiServer;
 import com.hp.hpl.jena.rdf.model.Model;
 import com.hp.hpl.jena.rdf.model.ModelFactory;
 import java.io.InputStream;
-import java.util.HashSet;
 import java.util.Iterator;
-import java.util.Set;
 import org.apache.commons.rdf.BlankNode;
 import org.apache.commons.rdf.BlankNodeOrIri;
 import org.apache.commons.rdf.Graph;
 import org.apache.commons.rdf.Iri;
-import org.apache.commons.rdf.Language;
-import org.apache.commons.rdf.Literal;
 import org.apache.commons.rdf.RdfTerm;
 import org.apache.commons.rdf.Triple;
-import org.apache.commons.rdf.impl.utils.PlainLiteralImpl;
 import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.BeforeClass;
-import org.junit.Ignore;
 import org.junit.Test;
 
 /**
@@ -71,10 +74,24 @@
     @Test
     public void nullFilter() {
         final Graph graph = new SparqlGraph("http://localhost:" + serverPort + "/ds/query");
+        final Iterator<Triple> iter = graph.filter(null, null, null);
+        Assert.assertTrue(iter.hasNext());
+        final Triple triple1 = iter.next();
+        final BlankNodeOrIri subject = triple1.getSubject();
+        final RdfTerm object = triple1.getObject();
+        Assert.assertTrue(subject instanceof BlankNode);
+        Assert.assertTrue(object instanceof BlankNode);
+        Assert.assertNotEquals(subject, object);
+        Assert.assertTrue(iter.hasNext());
+    }
+    
+    @Test
+    public void foafKnowsFilter() {
+        final Graph graph = new SparqlGraph("http://localhost:" + serverPort + "/ds/query");
         
         final Iri foafKnows = new Iri("http://xmlns.com/foaf/0.1/knows");
 
-        final Iterator<Triple> iter = graph.filter(null, null, null);
+        final Iterator<Triple> iter = graph.filter(null, foafKnows, null);
         Assert.assertTrue(iter.hasNext());
         final Triple triple1 = iter.next();
         final BlankNodeOrIri subject = triple1.getSubject();
diff --git a/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/BNodeTest.java b/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/BNodeTest.java
index a376fcd..f0a4aff 100644
--- a/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/BNodeTest.java
+++ b/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/BNodeTest.java
@@ -1,35 +1,38 @@
 /*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
+ * Copyright 2015 The Apache Software Foundation.
+ *
+ * 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 org.apache.commons.rdf.impl.sparql;
 
 import com.hp.hpl.jena.query.DatasetAccessor;
 import com.hp.hpl.jena.query.DatasetAccessorFactory;
-import java.io.File;
 import java.io.IOException;
 import java.net.ServerSocket;
 import org.apache.jena.fuseki.EmbeddedFusekiServer;
 import com.hp.hpl.jena.rdf.model.Model;
 import com.hp.hpl.jena.rdf.model.ModelFactory;
 import java.io.InputStream;
-import java.util.HashSet;
 import java.util.Iterator;
-import java.util.Set;
 import org.apache.commons.rdf.BlankNode;
 import org.apache.commons.rdf.BlankNodeOrIri;
 import org.apache.commons.rdf.Graph;
 import org.apache.commons.rdf.Iri;
-import org.apache.commons.rdf.Language;
-import org.apache.commons.rdf.Literal;
 import org.apache.commons.rdf.RdfTerm;
 import org.apache.commons.rdf.Triple;
-import org.apache.commons.rdf.impl.utils.PlainLiteralImpl;
 import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.BeforeClass;
-import org.junit.Ignore;
 import org.junit.Test;
 
 /**
@@ -105,7 +108,6 @@
         Assert.assertEquals(namedThing, knownThing);
     }
     
-    @Ignore
     @Test
     public void filter1() {
         final Graph graph = new SparqlGraph("http://localhost:" + serverPort + "/ds/query");
diff --git a/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/SimilarBNodes.java b/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/SimilarBNodes.java
index 1f52c4b..6300281 100644
--- a/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/SimilarBNodes.java
+++ b/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/SimilarBNodes.java
@@ -1,13 +1,20 @@
+/*
+ * Copyright 2015 The Apache Software Foundation.
+ *
+ * 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 org.apache.commons.rdf.impl.sparql;
 
-/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
- */
-
-
-import org.apache.commons.rdf.impl.sparql.*;
 import com.hp.hpl.jena.query.DatasetAccessor;
 import com.hp.hpl.jena.query.DatasetAccessorFactory;
 import java.io.IOException;
@@ -21,7 +28,6 @@
 import org.apache.commons.rdf.BlankNodeOrIri;
 import org.apache.commons.rdf.Graph;
 import org.apache.commons.rdf.Iri;
-import org.apache.commons.rdf.RdfTerm;
 import org.apache.commons.rdf.Triple;
 import org.junit.AfterClass;
 import org.junit.Assert;
diff --git a/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/SparqlGraphTest.java b/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/SparqlGraphTest.java
index e75bc2c..0c39e9d 100644
--- a/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/SparqlGraphTest.java
+++ b/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/SparqlGraphTest.java
@@ -1,13 +1,22 @@
 /*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
+ * Copyright 2015 The Apache Software Foundation.
+ *
+ * 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 org.apache.commons.rdf.impl.sparql;
 
 import com.hp.hpl.jena.query.DatasetAccessor;
 import com.hp.hpl.jena.query.DatasetAccessorFactory;
-import java.io.File;
 import java.io.IOException;
 import java.net.ServerSocket;
 import org.apache.jena.fuseki.EmbeddedFusekiServer;