JENA-625, prepare for jena-csv 1.0 release:
1. modify dependency from SNAPSHOT to release
2. refactor the package layout
3. move LangCSV from jena-arq module to jena-csv
4. modify jena-csv version to 1.0

git-svn-id: http://svn.apache.org/repos/asf/jena/Experimental/jena-csv@1618100 
13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/74c4bd06
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/74c4bd06
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/74c4bd06

Branch: refs/heads/master
Commit: 74c4bd06f1b8dbc63989887cc525a159ed4b1be3
Parents: e7e9229
Author: Ying Jiang <[email protected]>
Authored: Fri Aug 15 05:37:29 2014 +0000
Committer: Ying Jiang <[email protected]>
Committed: Fri Aug 15 05:37:29 2014 +0000

----------------------------------------------------------------------
 pom.xml                                         |  29 +-
 .../jena/propertytable/graph/GraphCSV.java      |  55 ++++
 .../propertytable/graph/GraphPropertyTable.java | 196 ++++++++++++++
 .../graph/QueryIterPropertyTable.java           | 120 +++++++++
 .../graph/QueryIterPropertyTableRow.java        | 237 +++++++++++++++++
 .../jena/propertytable/graph/RowMatch.java      |  44 ++++
 .../graph/StageGeneratorPropertyTable.java      |  56 ++++
 .../jena/propertytable/impl/GraphCSV.java       |  54 ----
 .../propertytable/impl/GraphPropertyTable.java  | 196 --------------
 .../impl/PropertyTableBuilder.java              |   2 +-
 .../impl/QueryIterPropertyTable.java            | 120 ---------
 .../impl/QueryIterPropertyTableRow.java         | 237 -----------------
 .../jena/propertytable/impl/RowMatch.java       |  44 ----
 .../impl/StageGeneratorPropertyTable.java       |  55 ----
 .../apache/jena/propertytable/lang/LangCSV.java | 225 ++++++++++++++++
 .../apache/jena/propertytable/util/IRILib.java  | 262 +++++++++++++++++++
 .../jena/propertytable/TS_PropertyTable.java    |   4 +-
 .../jena/propertytable/graph/GraphCSVTest.java  | 149 +++++++++++
 .../jena/propertytable/impl/GraphCSVTest.java   | 142 ----------
 .../jena/propertytable/lang/TestLangCSV.java    | 107 ++++++++
 20 files changed, 1474 insertions(+), 860 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/74c4bd06/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index ad246ac..457532b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,21 +22,30 @@
   <artifactId>jena-csv</artifactId>
   <packaging>jar</packaging>
   <name>Apache Jena - Data Tables for SPARQL</name>
-  <version>0.1-SNAPSHOT</version>
+  <version>1.0</version>
 
   <parent>
     <groupId>org.apache.jena</groupId>
     <artifactId>jena-parent</artifactId>
-    <version>10-SNAPSHOT</version>
+    <version>10</version>
     <relativePath>../jena-parent</relativePath>
   </parent>
-
+  
+    <!-- Need if the parent is a snapshot -->
+  <repositories>
+    <repository>
+      <id>apache.snapshots</id>
+      <name>Apache Snapshot Repository</name>
+      <url>http://repository.apache.org/snapshots</url>
+      <releases>
+       <enabled>false</enabled>
+      </releases>
+    </repository>
+  </repositories>
+  
+  <description>jena-csv is for getting CSVs into a form that is amenable to 
Jena SPARQL processing, and doing so in a way that is not specific to CSV 
files. It includes getting the right architecture in place for regular table 
shaped data, using the core abstraction of PropertyTable.</description> 
+  
   <properties>
-    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-
-    <jdk.version>1.6</jdk.version>
-    <targetJdk>${jdk.version}</targetJdk> <!-- MPMD-86 workaround -->
-    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     
<maven.build.timestamp.format>yyyy-MM-dd'T'HH:mm:ssZ</maven.build.timestamp.format>
     <build.time.xsd>${maven.build.timestamp}</build.time.xsd>
   </properties>
@@ -47,7 +56,7 @@
     <dependency>
       <groupId>org.apache.jena</groupId>
       <artifactId>apache-jena-libs</artifactId>
-      <version>2.12.1-SNAPSHOT</version>
+      <version>2.12.0</version>
       <type>pom</type>
     </dependency>
     
@@ -62,7 +71,7 @@
     <dependency>
       <groupId>org.apache.jena</groupId>
       <artifactId>jena-arq</artifactId>
-      <version>2.12.1-SNAPSHOT</version>
+      <version>2.12.0</version>
       <type>jar</type>
       <classifier>tests</classifier>
       <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/jena/blob/74c4bd06/src/main/java/org/apache/jena/propertytable/graph/GraphCSV.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/jena/propertytable/graph/GraphCSV.java 
b/src/main/java/org/apache/jena/propertytable/graph/GraphCSV.java
new file mode 100644
index 0000000..54ad131
--- /dev/null
+++ b/src/main/java/org/apache/jena/propertytable/graph/GraphCSV.java
@@ -0,0 +1,55 @@
+/*
+ * 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.jena.propertytable.graph;
+
+import org.apache.jena.propertytable.PropertyTable;
+import org.apache.jena.propertytable.impl.PropertyTableBuilder;
+
+
+public class GraphCSV extends GraphPropertyTable {
+       
+       public static GraphCSV createHashMapImpl( String csvFilePath ){
+               return new GraphCSVHashMapImpl(csvFilePath);
+       }
+       
+       public static GraphCSV createArrayImpl( String csvFilePath ){
+               return new GraphCSVArrayImpl(csvFilePath);
+       }
+       
+       protected GraphCSV (PropertyTable table) {
+               super(table);
+       }
+       
+       public GraphCSV ( String csvFilePath ){
+               
super(PropertyTableBuilder.buildPropetyTableArrayImplFromCsv(csvFilePath));
+       }
+}
+
+
+class GraphCSVHashMapImpl extends GraphCSV{
+       protected GraphCSVHashMapImpl(String csvFilePath){
+               
super(PropertyTableBuilder.buildPropetyTableHashMapImplFromCsv(csvFilePath));
+       }
+}
+
+class GraphCSVArrayImpl extends GraphCSV{
+       protected GraphCSVArrayImpl(String csvFilePath){
+               
super(PropertyTableBuilder.buildPropetyTableArrayImplFromCsv(csvFilePath));
+       }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/74c4bd06/src/main/java/org/apache/jena/propertytable/graph/GraphPropertyTable.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/jena/propertytable/graph/GraphPropertyTable.java 
b/src/main/java/org/apache/jena/propertytable/graph/GraphPropertyTable.java
new file mode 100644
index 0000000..8054279
--- /dev/null
+++ b/src/main/java/org/apache/jena/propertytable/graph/GraphPropertyTable.java
@@ -0,0 +1,196 @@
+/*
+ * 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.jena.propertytable.graph;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+import org.apache.jena.propertytable.Column;
+import org.apache.jena.propertytable.PropertyTable;
+import org.apache.jena.propertytable.Row;
+
+
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.graph.NodeFactory;
+import com.hp.hpl.jena.graph.Triple;
+import com.hp.hpl.jena.graph.TripleMatch;
+import com.hp.hpl.jena.graph.impl.GraphBase;
+import com.hp.hpl.jena.sparql.core.BasicPattern;
+import com.hp.hpl.jena.util.iterator.ExtendedIterator;
+import com.hp.hpl.jena.util.iterator.Filter;
+import com.hp.hpl.jena.util.iterator.NullIterator;
+import com.hp.hpl.jena.util.iterator.WrappedIterator;
+
+public class GraphPropertyTable extends GraphBase {
+
+       private PropertyTable pt;
+
+       public GraphPropertyTable(PropertyTable pt) {
+               this.pt = pt;
+       }
+
+       public PropertyTable getPropertyTable() {
+               return pt;
+       }
+
+       @Override
+       protected ExtendedIterator<Triple> graphBaseFind(TripleMatch m) {
+               //System.out.println(m);
+
+               if (this.pt == null) {
+                       return NullIterator.instance();
+               }
+
+               ExtendedIterator<Triple> iter = null;
+
+               Node s = m.getMatchSubject();
+               Node p = m.getMatchPredicate();
+               Node o = m.getMatchObject();
+
+               if (isConcrete(p) && isConcrete(o)) {
+                       //System.out.println("1");
+                       iter = pt.getTripleIterator(pt.getColumn(p), o);
+               } else if (isConcrete(p)) {
+                       //System.out.println("2");
+                       Column column = this.pt.getColumn(p);
+                       if (column != null) {
+                               iter = pt.getTripleIterator(column);
+                       } else {
+                               return NullIterator.instance();
+                       }
+               } else if (isConcrete(o)) {
+                       //System.out.println("3");
+                       iter = pt.getTripleIterator(o);
+               } else{
+                       //System.out.println("4");
+                       iter = pt.getTripleIterator();
+               }
+
+               return iter.filterKeep(new 
TripleMatchFilterEquality(m.asTriple()));
+
+       }
+       
+       protected ExtendedIterator<Row> propertyTableBaseFind(RowMatch m) {
+               
+               if (this.pt == null) {
+                       return NullIterator.instance();
+               }
+               
+               ExtendedIterator<Row> iter = null;
+
+               Node s = m.getMatchSubject();
+
+               if ( isConcrete(s) ){
+                       Row row= pt.getRow(s);
+                       if (row == null){
+                               return NullIterator.instance();
+                       } else {
+                               ArrayList<Row> rows = new ArrayList<Row>();
+                               rows.add(row);
+                               return WrappedIterator.create(rows.iterator());
+                       }
+               } else {
+                       iter = 
WrappedIterator.create(pt.getAllRows().iterator());
+               }
+               
+               return iter.filterKeep(new RowMatchFilterEquality( m ));
+               
+       }
+       
+       static class RowMatchFilterEquality extends Filter<Row> {
+               final protected RowMatch rMatch;
+
+               public RowMatchFilterEquality(RowMatch rMatch) {
+                       this.rMatch = rMatch;
+               }
+
+               @Override
+               public boolean accept(Row r) {
+                       return rowContained(rMatch, r);
+               }
+
+       }
+       
+       static boolean rowContained(RowMatch rMatch, Row row) {
+                       
+               boolean contained = equalNode(rMatch.getSubject(), 
row.getRowKey());
+               if(contained){
+                       BasicPattern pattern =rMatch.getBasicPattern();
+                       for(Triple triple: pattern ){
+                               contained = equalNode(triple.getObject(), 
row.getValue( triple.getPredicate()) );
+                               if (! contained){
+                                       break;
+                               }
+                       }
+               } 
+               return contained;
+       }
+       
+
+       static class TripleMatchFilterEquality extends Filter<Triple> {
+               final protected Triple tMatch;
+
+               /** Creates new TripleMatchFilter */
+               public TripleMatchFilterEquality(Triple tMatch) {
+                       this.tMatch = tMatch;
+               }
+
+               @Override
+               public boolean accept(Triple t) {
+                       return tripleContained(tMatch, t);
+               }
+
+       }
+
+       static boolean tripleContained(Triple patternTriple, Triple dataTriple) 
{
+               return equalNode(patternTriple.getSubject(), 
dataTriple.getSubject())
+                               && equalNode(patternTriple.getPredicate(),
+                                               dataTriple.getPredicate())
+                               && equalNode(patternTriple.getObject(), 
dataTriple.getObject());
+       }
+
+       private static boolean equalNode(Node m, Node n) {
+               // m should not be null unless .getMatchXXXX used to get the 
node.
+               // Language tag canonicalization
+               n = fixupNode(n);
+               m = fixupNode(m);
+               return (m == null) || (m == Node.ANY) || m.equals(n);
+       }
+
+       private static Node fixupNode(Node node) {
+               if (node == null || node == Node.ANY)
+                       return node;
+
+               // RDF says ... language tags should be canonicalized to lower 
case.
+               if (node.isLiteral()) {
+                       String lang = node.getLiteralLanguage();
+                       if (lang != null && !lang.equals(""))
+                               node = 
NodeFactory.createLiteral(node.getLiteralLexicalForm(),
+                                               lang.toLowerCase(Locale.ROOT),
+                                               node.getLiteralDatatype());
+               }
+               return node;
+       }
+
+       private boolean isConcrete(Node node) {
+               boolean wild = (node == null || node == Node.ANY);
+               return !wild;
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/74c4bd06/src/main/java/org/apache/jena/propertytable/graph/QueryIterPropertyTable.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/jena/propertytable/graph/QueryIterPropertyTable.java 
b/src/main/java/org/apache/jena/propertytable/graph/QueryIterPropertyTable.java
new file mode 100644
index 0000000..0d737fb
--- /dev/null
+++ 
b/src/main/java/org/apache/jena/propertytable/graph/QueryIterPropertyTable.java
@@ -0,0 +1,120 @@
+/*
+ * 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.jena.propertytable.graph;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+
+import org.apache.jena.atlas.io.IndentedWriter;
+
+import com.hp.hpl.jena.graph.Graph;
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.graph.Triple;
+import com.hp.hpl.jena.sparql.core.BasicPattern;
+import com.hp.hpl.jena.sparql.engine.ExecutionContext;
+import com.hp.hpl.jena.sparql.engine.QueryIterator;
+import com.hp.hpl.jena.sparql.engine.binding.Binding;
+import com.hp.hpl.jena.sparql.engine.iterator.QueryIter1;
+import com.hp.hpl.jena.sparql.serializer.SerializationContext;
+import com.hp.hpl.jena.sparql.util.FmtUtils;
+import com.hp.hpl.jena.sparql.util.Utils;
+
+public class QueryIterPropertyTable extends QueryIter1
+       {
+           private BasicPattern pattern ;
+           private Graph graph ;
+           private QueryIterator output ;
+           
+           public static QueryIterator create(QueryIterator input,
+                                              BasicPattern pattern , 
+                                              ExecutionContext execContext)
+           {
+               return new QueryIterPropertyTable(input, pattern, execContext) ;
+           }
+           
+           private QueryIterPropertyTable(QueryIterator input,
+                                           BasicPattern pattern , 
+                                           ExecutionContext execContext)
+           {
+               super(input, execContext) ;
+               this.pattern = pattern ;
+               graph = execContext.getActiveGraph() ;
+               // Create a chain of triple iterators.
+               QueryIterator chain = getInput() ;
+               Collection<BasicPattern> patterns = sort(pattern);
+               for (BasicPattern p : patterns)
+                   chain = new QueryIterPropertyTableRow(chain, p, 
execContext) ;
+               output = chain ;
+           }
+           
+           private Collection<BasicPattern> sort(BasicPattern pattern){
+               HashMap<Node, BasicPattern> map= new HashMap<Node, 
BasicPattern>();
+               for(Triple triple: pattern.getList()){
+                       Node subject = triple.getSubject();
+                       if(! map.containsKey(subject)){
+                               List<Triple> triples = new ArrayList<Triple>();
+                               BasicPattern p = BasicPattern.wrap(triples);
+                               map.put(subject, p);
+                               p.add(triple);
+                       }else {
+                               map.get(subject).add(triple);
+                       }
+               }
+               return map.values();
+           }
+
+           @Override
+           protected boolean hasNextBinding()
+           {
+               return output.hasNext() ;
+           }
+
+           @Override
+           protected Binding moveToNextBinding()
+           {
+               return output.nextBinding() ;
+           }
+
+           @Override
+           protected void closeSubIterator()
+           {
+               if ( output != null )
+                   output.close() ;
+               output = null ;
+           }
+           
+           @Override
+           protected void requestSubCancel()
+           {
+               if ( output != null )
+                   output.cancel();
+           }
+
+           @Override
+           protected void details(IndentedWriter out, SerializationContext 
sCxt)
+           {
+               out.print(Utils.className(this)) ;
+               out.println() ;
+               out.incIndent() ;
+               FmtUtils.formatPattern(out, pattern, sCxt) ;
+               out.decIndent() ;
+           }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/74c4bd06/src/main/java/org/apache/jena/propertytable/graph/QueryIterPropertyTableRow.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/jena/propertytable/graph/QueryIterPropertyTableRow.java
 
b/src/main/java/org/apache/jena/propertytable/graph/QueryIterPropertyTableRow.java
new file mode 100644
index 0000000..16f6723
--- /dev/null
+++ 
b/src/main/java/org/apache/jena/propertytable/graph/QueryIterPropertyTableRow.java
@@ -0,0 +1,237 @@
+/*
+ * 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.jena.propertytable.graph;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.jena.propertytable.PropertyTable;
+import org.apache.jena.propertytable.Row;
+
+
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.graph.Triple;
+import com.hp.hpl.jena.sparql.ARQInternalErrorException;
+import com.hp.hpl.jena.sparql.core.BasicPattern;
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.engine.ExecutionContext;
+import com.hp.hpl.jena.sparql.engine.QueryIterator;
+import com.hp.hpl.jena.sparql.engine.binding.Binding;
+import com.hp.hpl.jena.sparql.engine.binding.BindingFactory;
+import com.hp.hpl.jena.sparql.engine.binding.BindingMap;
+import com.hp.hpl.jena.sparql.engine.iterator.QueryIter;
+import com.hp.hpl.jena.sparql.engine.iterator.QueryIterRepeatApply;
+import com.hp.hpl.jena.util.iterator.ClosableIterator;
+import com.hp.hpl.jena.util.iterator.ExtendedIterator;
+import com.hp.hpl.jena.util.iterator.NiceIterator;
+import com.hp.hpl.jena.util.iterator.WrappedIterator;
+
+public class QueryIterPropertyTableRow  extends QueryIterRepeatApply{
+    private final BasicPattern pattern ;
+    
+    public QueryIterPropertyTableRow( QueryIterator input,
+                                   BasicPattern pattern , 
+                                   ExecutionContext cxt)
+    {
+        super(input, cxt) ;
+        this.pattern = pattern ;
+    }
+
+    @Override
+    protected QueryIterator nextStage(Binding binding)
+    {
+        return new RowMapper(binding, pattern, getExecContext()) ;
+    }
+    
+    static int countMapper = 0 ; 
+    static class RowMapper extends QueryIter
+    {   
+       private PropertyTable table;
+       
+       private BasicPattern pattern;
+        private Binding binding ;
+        private ClosableIterator<Row> graphIter ;
+        private Binding slot = null ;
+        private boolean finished = false ;
+        private volatile boolean cancelled = false ;
+
+        RowMapper(Binding binding, BasicPattern pattern, ExecutionContext cxt)
+        {
+            super(cxt) ;
+            GraphPropertyTable graph = 
(GraphPropertyTable)cxt.getActiveGraph() ;
+            
+            this.pattern = substitute(pattern, binding);
+            this.binding = binding ;
+            BasicPattern pattern2 = tripleNode(pattern);
+            
+            ExtendedIterator<Row> iter = graph.propertyTableBaseFind( new 
RowMatch( pattern2) );
+            
+            if ( false )
+            {
+                // Materialize the results now. Debugging only.
+                List<Row> x = iter.toList() ;
+                this.graphIter = WrappedIterator.create(x.iterator()) ;
+                iter.close();
+            }
+            else
+                // Stream.
+                this.graphIter = iter ;
+        }
+
+        private static Node tripleNode(Node node)
+        {
+            if ( node.isVariable() )
+                return Node.ANY ;
+            return node ;
+        }
+        
+        private static BasicPattern tripleNode(BasicPattern pattern)
+        {
+               List<Triple> triples = new ArrayList<Triple>();
+               for (Triple triple: pattern){
+                       triples.add( tripleNode(triple) );
+               }
+               return BasicPattern.wrap(triples);
+        }
+        
+        private static Triple tripleNode(Triple triple){
+            Node s = tripleNode(triple.getSubject()) ;
+            Node p = tripleNode(triple.getPredicate()) ;
+            Node o = tripleNode(triple.getObject()) ;
+            return Triple.create(s, p, o);
+        }
+
+        private static Node substitute(Node node, Binding binding)
+        {
+            if ( Var.isVar(node) )
+            {
+                Node x = binding.get(Var.alloc(node)) ;
+                if ( x != null )
+                    return x ;
+            }
+            return node ;
+        }
+        
+        private static Triple substitute(Triple triple, Binding binding){
+            Node s = substitute(triple.getSubject(), binding) ;
+            Node p = substitute(triple.getPredicate(), binding) ;
+            Node o = substitute(triple.getObject(), binding) ;
+            return Triple.create(s, p, o);
+        }
+        
+        private static BasicPattern substitute(BasicPattern pattern , Binding 
binding)
+        {
+               List<Triple> triples = new ArrayList<Triple>();
+               for (Triple triple: pattern){
+                       triples.add( substitute(triple,binding) );
+               }
+               return BasicPattern.wrap(triples);
+        }
+        
+        private Binding mapper(Row r)
+        {
+            BindingMap results = BindingFactory.create(binding) ;
+
+            if ( ! insert(pattern, r, results) )
+                return null ; 
+            return results ;
+        }
+        
+        private static boolean insert(BasicPattern input, Row output, 
BindingMap results)
+        {      
+               for (Triple triple: input){
+                       if (! insert(triple, output, results) ){
+                               return false;
+                       }
+               }
+               return true;
+        }
+        
+        private static boolean insert(Triple input, Row output, BindingMap 
results){
+               if ( ! insert(input.getSubject(), output.getRowKey(), results) )
+                return false ;
+//             if ( ! insert(input.getPredicate(), output.get, results) )
+//                return false ;
+            if ( ! insert(input.getObject(), output.getValue( 
input.getPredicate() ), results) )
+                return false ;
+            return true;
+        }
+
+        private static boolean insert(Node inputNode, Node outputNode, 
BindingMap results)
+        {
+            if ( ! Var.isVar(inputNode) )
+                return true ;
+            
+            Var v = Var.alloc(inputNode) ;
+            Node x = results.get(v) ;
+            if ( x != null )
+                return outputNode.equals(x) ;
+            
+            results.add(v, outputNode) ;
+            return true ;
+        }
+        
+        @Override
+        protected boolean hasNextBinding()
+        {
+            if ( finished ) return false ;
+            if ( slot != null ) return true ;
+            if ( cancelled )
+            {
+                graphIter.close() ;
+                finished = true ;
+                return false ;
+            }
+
+            while(graphIter.hasNext() && slot == null )
+            {
+                Row r = graphIter.next() ;
+                slot = mapper(r) ;
+            }
+            if ( slot == null )
+                finished = true ;
+            return slot != null ;
+        }
+
+        @Override
+        protected Binding moveToNextBinding()
+        {
+            if ( ! hasNextBinding() ) 
+                throw new ARQInternalErrorException() ;
+            Binding r = slot ;
+            slot = null ;
+            return r ;
+        }
+
+        @Override
+        protected void closeIterator()
+        {
+            if ( graphIter != null )
+                NiceIterator.close(graphIter) ;
+            graphIter = null ;
+        }
+        
+        @Override
+        protected void requestCancel()
+        {
+            // The QueryIteratorBase machinary will do the real work.
+            cancelled = true ;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/74c4bd06/src/main/java/org/apache/jena/propertytable/graph/RowMatch.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/jena/propertytable/graph/RowMatch.java 
b/src/main/java/org/apache/jena/propertytable/graph/RowMatch.java
new file mode 100644
index 0000000..3310807
--- /dev/null
+++ b/src/main/java/org/apache/jena/propertytable/graph/RowMatch.java
@@ -0,0 +1,44 @@
+/*
+ * 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.jena.propertytable.graph;
+
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.sparql.core.BasicPattern;
+
+public class RowMatch {
+       
+       private BasicPattern pattern;
+       
+       public RowMatch( BasicPattern pattern ){                
+               this.pattern=pattern;
+       }
+
+       public Node getMatchSubject(){
+               return pattern.get(0).getMatchSubject();
+       }
+       
+       public Node getSubject(){
+               return pattern.get(0).getSubject();
+       }
+       
+       public BasicPattern getBasicPattern(){
+               return pattern;
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/74c4bd06/src/main/java/org/apache/jena/propertytable/graph/StageGeneratorPropertyTable.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/jena/propertytable/graph/StageGeneratorPropertyTable.java
 
b/src/main/java/org/apache/jena/propertytable/graph/StageGeneratorPropertyTable.java
new file mode 100644
index 0000000..c601000
--- /dev/null
+++ 
b/src/main/java/org/apache/jena/propertytable/graph/StageGeneratorPropertyTable.java
@@ -0,0 +1,56 @@
+/*
+ * 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.jena.propertytable.graph;
+
+
+import com.hp.hpl.jena.graph.Graph;
+import com.hp.hpl.jena.sparql.core.BasicPattern;
+import com.hp.hpl.jena.sparql.engine.ExecutionContext;
+import com.hp.hpl.jena.sparql.engine.QueryIterator;
+import com.hp.hpl.jena.sparql.engine.main.StageGenerator;
+
+public class StageGeneratorPropertyTable implements StageGenerator {
+
+    // Using OpExecutor is preferred.
+    StageGenerator above = null ;
+    
+    public StageGeneratorPropertyTable(StageGenerator original)
+    {
+        above = original ;
+    }
+    
+    @Override
+    public QueryIterator execute(BasicPattern pattern, QueryIterator input, 
ExecutionContext execCxt)
+    {
+        // --- In case this isn't for GraphPropertyTable
+        Graph g = execCxt.getActiveGraph() ;
+        
+        if ( ! ( g instanceof GraphPropertyTable ) )
+            // Not us - bounce up the StageGenerator chain
+            return above.execute(pattern, input, execCxt) ;
+        if (pattern.size() <= 1){
+//             System.out.println( "<=1 "+ pattern);
+               return above.execute(pattern, input, execCxt) ;
+        }
+//        System.out.println( ">1" + pattern);
+        return QueryIterPropertyTable.create(input, pattern, execCxt);
+    }
+    
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/74c4bd06/src/main/java/org/apache/jena/propertytable/impl/GraphCSV.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/jena/propertytable/impl/GraphCSV.java 
b/src/main/java/org/apache/jena/propertytable/impl/GraphCSV.java
deleted file mode 100644
index 6ae4514..0000000
--- a/src/main/java/org/apache/jena/propertytable/impl/GraphCSV.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.jena.propertytable.impl;
-
-import org.apache.jena.propertytable.PropertyTable;
-
-
-public class GraphCSV extends GraphPropertyTable {
-       
-       public static GraphCSV createHashMapImpl( String csvFilePath ){
-               return new GraphCSVHashMapImpl(csvFilePath);
-       }
-       
-       public static GraphCSV createArrayImpl( String csvFilePath ){
-               return new GraphCSVArrayImpl(csvFilePath);
-       }
-       
-       protected GraphCSV (PropertyTable table) {
-               super(table);
-       }
-       
-       public GraphCSV ( String csvFilePath ){
-               
super(PropertyTableBuilder.buildPropetyTableArrayImplFromCsv(csvFilePath));
-       }
-}
-
-
-class GraphCSVHashMapImpl extends GraphCSV{
-       protected GraphCSVHashMapImpl(String csvFilePath){
-               
super(PropertyTableBuilder.buildPropetyTableHashMapImplFromCsv(csvFilePath));
-       }
-}
-
-class GraphCSVArrayImpl extends GraphCSV{
-       protected GraphCSVArrayImpl(String csvFilePath){
-               
super(PropertyTableBuilder.buildPropetyTableArrayImplFromCsv(csvFilePath));
-       }
-}

http://git-wip-us.apache.org/repos/asf/jena/blob/74c4bd06/src/main/java/org/apache/jena/propertytable/impl/GraphPropertyTable.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/jena/propertytable/impl/GraphPropertyTable.java 
b/src/main/java/org/apache/jena/propertytable/impl/GraphPropertyTable.java
deleted file mode 100644
index 3188bcb..0000000
--- a/src/main/java/org/apache/jena/propertytable/impl/GraphPropertyTable.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * 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.jena.propertytable.impl;
-
-import java.util.ArrayList;
-import java.util.Locale;
-
-import org.apache.jena.propertytable.Column;
-import org.apache.jena.propertytable.PropertyTable;
-import org.apache.jena.propertytable.Row;
-
-
-import com.hp.hpl.jena.graph.Node;
-import com.hp.hpl.jena.graph.NodeFactory;
-import com.hp.hpl.jena.graph.Triple;
-import com.hp.hpl.jena.graph.TripleMatch;
-import com.hp.hpl.jena.graph.impl.GraphBase;
-import com.hp.hpl.jena.sparql.core.BasicPattern;
-import com.hp.hpl.jena.util.iterator.ExtendedIterator;
-import com.hp.hpl.jena.util.iterator.Filter;
-import com.hp.hpl.jena.util.iterator.NullIterator;
-import com.hp.hpl.jena.util.iterator.WrappedIterator;
-
-public class GraphPropertyTable extends GraphBase {
-
-       private PropertyTable pt;
-
-       public GraphPropertyTable(PropertyTable pt) {
-               this.pt = pt;
-       }
-
-       public PropertyTable getPropertyTable() {
-               return pt;
-       }
-
-       @Override
-       protected ExtendedIterator<Triple> graphBaseFind(TripleMatch m) {
-               //System.out.println(m);
-
-               if (this.pt == null) {
-                       return NullIterator.instance();
-               }
-
-               ExtendedIterator<Triple> iter = null;
-
-               Node s = m.getMatchSubject();
-               Node p = m.getMatchPredicate();
-               Node o = m.getMatchObject();
-
-               if (isConcrete(p) && isConcrete(o)) {
-                       //System.out.println("1");
-                       iter = pt.getTripleIterator(pt.getColumn(p), o);
-               } else if (isConcrete(p)) {
-                       //System.out.println("2");
-                       Column column = this.pt.getColumn(p);
-                       if (column != null) {
-                               iter = pt.getTripleIterator(column);
-                       } else {
-                               return NullIterator.instance();
-                       }
-               } else if (isConcrete(o)) {
-                       //System.out.println("3");
-                       iter = pt.getTripleIterator(o);
-               } else{
-                       //System.out.println("4");
-                       iter = pt.getTripleIterator();
-               }
-
-               return iter.filterKeep(new 
TripleMatchFilterEquality(m.asTriple()));
-
-       }
-       
-       protected ExtendedIterator<Row> propertyTableBaseFind(RowMatch m) {
-               
-               if (this.pt == null) {
-                       return NullIterator.instance();
-               }
-               
-               ExtendedIterator<Row> iter = null;
-
-               Node s = m.getMatchSubject();
-
-               if ( isConcrete(s) ){
-                       Row row= pt.getRow(s);
-                       if (row == null){
-                               return NullIterator.instance();
-                       } else {
-                               ArrayList<Row> rows = new ArrayList<Row>();
-                               rows.add(row);
-                               return WrappedIterator.create(rows.iterator());
-                       }
-               } else {
-                       iter = 
WrappedIterator.create(pt.getAllRows().iterator());
-               }
-               
-               return iter.filterKeep(new RowMatchFilterEquality( m ));
-               
-       }
-       
-       static class RowMatchFilterEquality extends Filter<Row> {
-               final protected RowMatch rMatch;
-
-               public RowMatchFilterEquality(RowMatch rMatch) {
-                       this.rMatch = rMatch;
-               }
-
-               @Override
-               public boolean accept(Row r) {
-                       return rowContained(rMatch, r);
-               }
-
-       }
-       
-       static boolean rowContained(RowMatch rMatch, Row row) {
-                       
-               boolean contained = equalNode(rMatch.getSubject(), 
row.getRowKey());
-               if(contained){
-                       BasicPattern pattern =rMatch.getBasicPattern();
-                       for(Triple triple: pattern ){
-                               contained = equalNode(triple.getObject(), 
row.getValue( triple.getPredicate()) );
-                               if (! contained){
-                                       break;
-                               }
-                       }
-               } 
-               return contained;
-       }
-       
-
-       static class TripleMatchFilterEquality extends Filter<Triple> {
-               final protected Triple tMatch;
-
-               /** Creates new TripleMatchFilter */
-               public TripleMatchFilterEquality(Triple tMatch) {
-                       this.tMatch = tMatch;
-               }
-
-               @Override
-               public boolean accept(Triple t) {
-                       return tripleContained(tMatch, t);
-               }
-
-       }
-
-       static boolean tripleContained(Triple patternTriple, Triple dataTriple) 
{
-               return equalNode(patternTriple.getSubject(), 
dataTriple.getSubject())
-                               && equalNode(patternTriple.getPredicate(),
-                                               dataTriple.getPredicate())
-                               && equalNode(patternTriple.getObject(), 
dataTriple.getObject());
-       }
-
-       private static boolean equalNode(Node m, Node n) {
-               // m should not be null unless .getMatchXXXX used to get the 
node.
-               // Language tag canonicalization
-               n = fixupNode(n);
-               m = fixupNode(m);
-               return (m == null) || (m == Node.ANY) || m.equals(n);
-       }
-
-       private static Node fixupNode(Node node) {
-               if (node == null || node == Node.ANY)
-                       return node;
-
-               // RDF says ... language tags should be canonicalized to lower 
case.
-               if (node.isLiteral()) {
-                       String lang = node.getLiteralLanguage();
-                       if (lang != null && !lang.equals(""))
-                               node = 
NodeFactory.createLiteral(node.getLiteralLexicalForm(),
-                                               lang.toLowerCase(Locale.ROOT),
-                                               node.getLiteralDatatype());
-               }
-               return node;
-       }
-
-       private boolean isConcrete(Node node) {
-               boolean wild = (node == null || node == Node.ANY);
-               return !wild;
-       }
-
-}

http://git-wip-us.apache.org/repos/asf/jena/blob/74c4bd06/src/main/java/org/apache/jena/propertytable/impl/PropertyTableBuilder.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/jena/propertytable/impl/PropertyTableBuilder.java 
b/src/main/java/org/apache/jena/propertytable/impl/PropertyTableBuilder.java
index 7a2a74f..0c625f7 100644
--- a/src/main/java/org/apache/jena/propertytable/impl/PropertyTableBuilder.java
+++ b/src/main/java/org/apache/jena/propertytable/impl/PropertyTableBuilder.java
@@ -27,7 +27,7 @@ import org.apache.jena.atlas.csv.CSVTokenIterator;
 import org.apache.jena.atlas.io.IO;
 import org.apache.jena.propertytable.PropertyTable;
 import org.apache.jena.propertytable.Row;
-import org.apache.jena.riot.lang.LangCSV;
+import org.apache.jena.propertytable.lang.LangCSV;
 import org.apache.jena.riot.system.IRIResolver;
 
 import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;

http://git-wip-us.apache.org/repos/asf/jena/blob/74c4bd06/src/main/java/org/apache/jena/propertytable/impl/QueryIterPropertyTable.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/jena/propertytable/impl/QueryIterPropertyTable.java 
b/src/main/java/org/apache/jena/propertytable/impl/QueryIterPropertyTable.java
deleted file mode 100644
index 1a9e350..0000000
--- 
a/src/main/java/org/apache/jena/propertytable/impl/QueryIterPropertyTable.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * 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.jena.propertytable.impl;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-
-import org.apache.jena.atlas.io.IndentedWriter;
-
-import com.hp.hpl.jena.graph.Graph;
-import com.hp.hpl.jena.graph.Node;
-import com.hp.hpl.jena.graph.Triple;
-import com.hp.hpl.jena.sparql.core.BasicPattern;
-import com.hp.hpl.jena.sparql.engine.ExecutionContext;
-import com.hp.hpl.jena.sparql.engine.QueryIterator;
-import com.hp.hpl.jena.sparql.engine.binding.Binding;
-import com.hp.hpl.jena.sparql.engine.iterator.QueryIter1;
-import com.hp.hpl.jena.sparql.serializer.SerializationContext;
-import com.hp.hpl.jena.sparql.util.FmtUtils;
-import com.hp.hpl.jena.sparql.util.Utils;
-
-public class QueryIterPropertyTable extends QueryIter1
-       {
-           private BasicPattern pattern ;
-           private Graph graph ;
-           private QueryIterator output ;
-           
-           public static QueryIterator create(QueryIterator input,
-                                              BasicPattern pattern , 
-                                              ExecutionContext execContext)
-           {
-               return new QueryIterPropertyTable(input, pattern, execContext) ;
-           }
-           
-           private QueryIterPropertyTable(QueryIterator input,
-                                           BasicPattern pattern , 
-                                           ExecutionContext execContext)
-           {
-               super(input, execContext) ;
-               this.pattern = pattern ;
-               graph = execContext.getActiveGraph() ;
-               // Create a chain of triple iterators.
-               QueryIterator chain = getInput() ;
-               Collection<BasicPattern> patterns = sort(pattern);
-               for (BasicPattern p : patterns)
-                   chain = new QueryIterPropertyTableRow(chain, p, 
execContext) ;
-               output = chain ;
-           }
-           
-           private Collection<BasicPattern> sort(BasicPattern pattern){
-               HashMap<Node, BasicPattern> map= new HashMap<Node, 
BasicPattern>();
-               for(Triple triple: pattern.getList()){
-                       Node subject = triple.getSubject();
-                       if(! map.containsKey(subject)){
-                               List<Triple> triples = new ArrayList<Triple>();
-                               BasicPattern p = BasicPattern.wrap(triples);
-                               map.put(subject, p);
-                               p.add(triple);
-                       }else {
-                               map.get(subject).add(triple);
-                       }
-               }
-               return map.values();
-           }
-
-           @Override
-           protected boolean hasNextBinding()
-           {
-               return output.hasNext() ;
-           }
-
-           @Override
-           protected Binding moveToNextBinding()
-           {
-               return output.nextBinding() ;
-           }
-
-           @Override
-           protected void closeSubIterator()
-           {
-               if ( output != null )
-                   output.close() ;
-               output = null ;
-           }
-           
-           @Override
-           protected void requestSubCancel()
-           {
-               if ( output != null )
-                   output.cancel();
-           }
-
-           @Override
-           protected void details(IndentedWriter out, SerializationContext 
sCxt)
-           {
-               out.print(Utils.className(this)) ;
-               out.println() ;
-               out.incIndent() ;
-               FmtUtils.formatPattern(out, pattern, sCxt) ;
-               out.decIndent() ;
-           }
-}

http://git-wip-us.apache.org/repos/asf/jena/blob/74c4bd06/src/main/java/org/apache/jena/propertytable/impl/QueryIterPropertyTableRow.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/jena/propertytable/impl/QueryIterPropertyTableRow.java
 
b/src/main/java/org/apache/jena/propertytable/impl/QueryIterPropertyTableRow.java
deleted file mode 100644
index c304f7d..0000000
--- 
a/src/main/java/org/apache/jena/propertytable/impl/QueryIterPropertyTableRow.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * 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.jena.propertytable.impl;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.jena.propertytable.PropertyTable;
-import org.apache.jena.propertytable.Row;
-
-
-import com.hp.hpl.jena.graph.Node;
-import com.hp.hpl.jena.graph.Triple;
-import com.hp.hpl.jena.sparql.ARQInternalErrorException;
-import com.hp.hpl.jena.sparql.core.BasicPattern;
-import com.hp.hpl.jena.sparql.core.Var;
-import com.hp.hpl.jena.sparql.engine.ExecutionContext;
-import com.hp.hpl.jena.sparql.engine.QueryIterator;
-import com.hp.hpl.jena.sparql.engine.binding.Binding;
-import com.hp.hpl.jena.sparql.engine.binding.BindingFactory;
-import com.hp.hpl.jena.sparql.engine.binding.BindingMap;
-import com.hp.hpl.jena.sparql.engine.iterator.QueryIter;
-import com.hp.hpl.jena.sparql.engine.iterator.QueryIterRepeatApply;
-import com.hp.hpl.jena.util.iterator.ClosableIterator;
-import com.hp.hpl.jena.util.iterator.ExtendedIterator;
-import com.hp.hpl.jena.util.iterator.NiceIterator;
-import com.hp.hpl.jena.util.iterator.WrappedIterator;
-
-public class QueryIterPropertyTableRow  extends QueryIterRepeatApply{
-    private final BasicPattern pattern ;
-    
-    public QueryIterPropertyTableRow( QueryIterator input,
-                                   BasicPattern pattern , 
-                                   ExecutionContext cxt)
-    {
-        super(input, cxt) ;
-        this.pattern = pattern ;
-    }
-
-    @Override
-    protected QueryIterator nextStage(Binding binding)
-    {
-        return new RowMapper(binding, pattern, getExecContext()) ;
-    }
-    
-    static int countMapper = 0 ; 
-    static class RowMapper extends QueryIter
-    {   
-       private PropertyTable table;
-       
-       private BasicPattern pattern;
-        private Binding binding ;
-        private ClosableIterator<Row> graphIter ;
-        private Binding slot = null ;
-        private boolean finished = false ;
-        private volatile boolean cancelled = false ;
-
-        RowMapper(Binding binding, BasicPattern pattern, ExecutionContext cxt)
-        {
-            super(cxt) ;
-            GraphPropertyTable graph = 
(GraphPropertyTable)cxt.getActiveGraph() ;
-            
-            this.pattern = substitute(pattern, binding);
-            this.binding = binding ;
-            BasicPattern pattern2 = tripleNode(pattern);
-            
-            ExtendedIterator<Row> iter = graph.propertyTableBaseFind( new 
RowMatch( pattern2) );
-            
-            if ( false )
-            {
-                // Materialize the results now. Debugging only.
-                List<Row> x = iter.toList() ;
-                this.graphIter = WrappedIterator.create(x.iterator()) ;
-                iter.close();
-            }
-            else
-                // Stream.
-                this.graphIter = iter ;
-        }
-
-        private static Node tripleNode(Node node)
-        {
-            if ( node.isVariable() )
-                return Node.ANY ;
-            return node ;
-        }
-        
-        private static BasicPattern tripleNode(BasicPattern pattern)
-        {
-               List<Triple> triples = new ArrayList<Triple>();
-               for (Triple triple: pattern){
-                       triples.add( tripleNode(triple) );
-               }
-               return BasicPattern.wrap(triples);
-        }
-        
-        private static Triple tripleNode(Triple triple){
-            Node s = tripleNode(triple.getSubject()) ;
-            Node p = tripleNode(triple.getPredicate()) ;
-            Node o = tripleNode(triple.getObject()) ;
-            return Triple.create(s, p, o);
-        }
-
-        private static Node substitute(Node node, Binding binding)
-        {
-            if ( Var.isVar(node) )
-            {
-                Node x = binding.get(Var.alloc(node)) ;
-                if ( x != null )
-                    return x ;
-            }
-            return node ;
-        }
-        
-        private static Triple substitute(Triple triple, Binding binding){
-            Node s = substitute(triple.getSubject(), binding) ;
-            Node p = substitute(triple.getPredicate(), binding) ;
-            Node o = substitute(triple.getObject(), binding) ;
-            return Triple.create(s, p, o);
-        }
-        
-        private static BasicPattern substitute(BasicPattern pattern , Binding 
binding)
-        {
-               List<Triple> triples = new ArrayList<Triple>();
-               for (Triple triple: pattern){
-                       triples.add( substitute(triple,binding) );
-               }
-               return BasicPattern.wrap(triples);
-        }
-        
-        private Binding mapper(Row r)
-        {
-            BindingMap results = BindingFactory.create(binding) ;
-
-            if ( ! insert(pattern, r, results) )
-                return null ; 
-            return results ;
-        }
-        
-        private static boolean insert(BasicPattern input, Row output, 
BindingMap results)
-        {      
-               for (Triple triple: input){
-                       if (! insert(triple, output, results) ){
-                               return false;
-                       }
-               }
-               return true;
-        }
-        
-        private static boolean insert(Triple input, Row output, BindingMap 
results){
-               if ( ! insert(input.getSubject(), output.getRowKey(), results) )
-                return false ;
-//             if ( ! insert(input.getPredicate(), output.get, results) )
-//                return false ;
-            if ( ! insert(input.getObject(), output.getValue( 
input.getPredicate() ), results) )
-                return false ;
-            return true;
-        }
-
-        private static boolean insert(Node inputNode, Node outputNode, 
BindingMap results)
-        {
-            if ( ! Var.isVar(inputNode) )
-                return true ;
-            
-            Var v = Var.alloc(inputNode) ;
-            Node x = results.get(v) ;
-            if ( x != null )
-                return outputNode.equals(x) ;
-            
-            results.add(v, outputNode) ;
-            return true ;
-        }
-        
-        @Override
-        protected boolean hasNextBinding()
-        {
-            if ( finished ) return false ;
-            if ( slot != null ) return true ;
-            if ( cancelled )
-            {
-                graphIter.close() ;
-                finished = true ;
-                return false ;
-            }
-
-            while(graphIter.hasNext() && slot == null )
-            {
-                Row r = graphIter.next() ;
-                slot = mapper(r) ;
-            }
-            if ( slot == null )
-                finished = true ;
-            return slot != null ;
-        }
-
-        @Override
-        protected Binding moveToNextBinding()
-        {
-            if ( ! hasNextBinding() ) 
-                throw new ARQInternalErrorException() ;
-            Binding r = slot ;
-            slot = null ;
-            return r ;
-        }
-
-        @Override
-        protected void closeIterator()
-        {
-            if ( graphIter != null )
-                NiceIterator.close(graphIter) ;
-            graphIter = null ;
-        }
-        
-        @Override
-        protected void requestCancel()
-        {
-            // The QueryIteratorBase machinary will do the real work.
-            cancelled = true ;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/jena/blob/74c4bd06/src/main/java/org/apache/jena/propertytable/impl/RowMatch.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/jena/propertytable/impl/RowMatch.java 
b/src/main/java/org/apache/jena/propertytable/impl/RowMatch.java
deleted file mode 100644
index cbd699a..0000000
--- a/src/main/java/org/apache/jena/propertytable/impl/RowMatch.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.jena.propertytable.impl;
-
-import com.hp.hpl.jena.graph.Node;
-import com.hp.hpl.jena.sparql.core.BasicPattern;
-
-public class RowMatch {
-       
-       private BasicPattern pattern;
-       
-       public RowMatch( BasicPattern pattern ){                
-               this.pattern=pattern;
-       }
-
-       public Node getMatchSubject(){
-               return pattern.get(0).getMatchSubject();
-       }
-       
-       public Node getSubject(){
-               return pattern.get(0).getSubject();
-       }
-       
-       public BasicPattern getBasicPattern(){
-               return pattern;
-       }
-
-}

http://git-wip-us.apache.org/repos/asf/jena/blob/74c4bd06/src/main/java/org/apache/jena/propertytable/impl/StageGeneratorPropertyTable.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/jena/propertytable/impl/StageGeneratorPropertyTable.java
 
b/src/main/java/org/apache/jena/propertytable/impl/StageGeneratorPropertyTable.java
deleted file mode 100644
index 68fb025..0000000
--- 
a/src/main/java/org/apache/jena/propertytable/impl/StageGeneratorPropertyTable.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.jena.propertytable.impl;
-
-import com.hp.hpl.jena.graph.Graph;
-import com.hp.hpl.jena.sparql.core.BasicPattern;
-import com.hp.hpl.jena.sparql.engine.ExecutionContext;
-import com.hp.hpl.jena.sparql.engine.QueryIterator;
-import com.hp.hpl.jena.sparql.engine.main.StageGenerator;
-
-public class StageGeneratorPropertyTable implements StageGenerator {
-
-    // Using OpExecutor is preferred.
-    StageGenerator above = null ;
-    
-    public StageGeneratorPropertyTable(StageGenerator original)
-    {
-        above = original ;
-    }
-    
-    @Override
-    public QueryIterator execute(BasicPattern pattern, QueryIterator input, 
ExecutionContext execCxt)
-    {
-        // --- In case this isn't for GraphPropertyTable
-        Graph g = execCxt.getActiveGraph() ;
-        
-        if ( ! ( g instanceof GraphPropertyTable ) )
-            // Not us - bounce up the StageGenerator chain
-            return above.execute(pattern, input, execCxt) ;
-        if (pattern.size() <= 1){
-//             System.out.println( "<=1 "+ pattern);
-               return above.execute(pattern, input, execCxt) ;
-        }
-//        System.out.println( ">1" + pattern);
-        return QueryIterPropertyTable.create(input, pattern, execCxt);
-    }
-    
-
-}

http://git-wip-us.apache.org/repos/asf/jena/blob/74c4bd06/src/main/java/org/apache/jena/propertytable/lang/LangCSV.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/jena/propertytable/lang/LangCSV.java 
b/src/main/java/org/apache/jena/propertytable/lang/LangCSV.java
new file mode 100644
index 0000000..d53f7a7
--- /dev/null
+++ b/src/main/java/org/apache/jena/propertytable/lang/LangCSV.java
@@ -0,0 +1,225 @@
+/**
+ * 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.jena.propertytable.lang;
+
+import static org.apache.jena.riot.RDFLanguages.CSV;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.jena.atlas.csv.CSVParser;
+import org.apache.jena.atlas.web.ContentType;
+import org.apache.jena.propertytable.util.IRILib;
+import org.apache.jena.riot.Lang;
+import org.apache.jena.riot.RDFLanguages;
+import org.apache.jena.riot.RDFParserRegistry;
+import org.apache.jena.riot.ReaderRIOT;
+import org.apache.jena.riot.ReaderRIOTFactory;
+import org.apache.jena.riot.lang.LangRIOT;
+import org.apache.jena.riot.system.ErrorHandler;
+import org.apache.jena.riot.system.ErrorHandlerFactory;
+import org.apache.jena.riot.system.IRIResolver;
+import org.apache.jena.riot.system.ParserProfile;
+import org.apache.jena.riot.system.RiotLib;
+import org.apache.jena.riot.system.StreamRDF;
+
+import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.graph.NodeFactory;
+import com.hp.hpl.jena.sparql.util.Context;
+
+public class LangCSV implements LangRIOT {
+
+       public static final String CSV_PREFIX = "http://w3c/future-csv-vocab/";;
+       public static final String CSV_ROW = CSV_PREFIX + "row";
+
+       private InputStream input = null;
+       private Reader reader = null;
+       private String base;
+       private String filename;
+       private StreamRDF sink;
+       private ParserProfile profile; // Warning - we don't use all of this.
+       
+       public static void register(){
+               RDFParserRegistry.removeRegistration(Lang.CSV);
+               RDFParserRegistry.registerLangTriples(Lang.CSV, new 
ReaderRIOTFactoryCSV());
+       }
+
+       @Override
+       public Lang getLang() {
+               return RDFLanguages.CSV;
+       }
+
+       @Override
+       public ParserProfile getProfile() {
+               return profile;
+       }
+
+       @Override
+       public void setProfile(ParserProfile profile) {
+               this.profile = profile;
+       }
+
+       public LangCSV(Reader reader, String base, String filename,
+                       ErrorHandler errorHandler, StreamRDF sink) {
+               this.reader = reader;
+               this.base = base;
+               this.filename = filename;
+               this.sink = sink;
+               this.profile = RiotLib.profile(getLang(), base, errorHandler);
+       }
+
+       public LangCSV(InputStream in, String base, String filename,
+                       ErrorHandler errorHandler, StreamRDF sink) {
+               this.input = in;
+               this.base = base;
+               this.filename = filename;
+               this.sink = sink;
+               this.profile = RiotLib.profile(getLang(), base, errorHandler);
+       }
+
+       @Override
+       public void parse() {
+               sink.start();
+               CSVParser parser = (input != null) ? CSVParser.create(input)
+                               : CSVParser.create(reader);
+               List<String> row = null;
+               ArrayList<Node> predicates = new ArrayList<Node>();
+               int rowNum = 0;
+               while ((row = parser.parse1()) != null) {
+                       
+                       if (rowNum == 0) {
+                               for (String column : row) {
+                                       String uri = 
IRIResolver.resolveString(filename) + "#"
+                                                       + 
toSafeLocalname(column);
+                                       Node predicate = 
this.profile.createURI(uri, rowNum, 0);
+                                       predicates.add(predicate);
+                               }
+                       } else {
+                               //Node subject = 
this.profile.createBlankNode(null, -1, -1);
+                               Node subject = caculateSubject(rowNum, 
filename);
+                               Node predicateRow = 
this.profile.createURI(CSV_ROW, -1, -1);
+                               Node objectRow = this.profile
+                                               .createTypedLiteral((rowNum + 
""),
+                                                               
XSDDatatype.XSDinteger, rowNum, 0);
+                               sink.triple(this.profile.createTriple(subject, 
predicateRow,
+                                               objectRow, rowNum, 0));
+                               for (int col = 0; col < row.size() && 
col<predicates.size(); col++) {
+                                       Node predicate = predicates.get(col);
+                                       String columnValue = 
row.get(col).trim();
+                                       if("".equals(columnValue)){
+                                               continue;
+                                       }                                       
+                                       Node o;
+                                       try {
+                                               // Try for a double.
+                                               double d = 
Double.parseDouble(columnValue);
+                                               o = 
NodeFactory.createLiteral(columnValue,
+                                                               
XSDDatatype.XSDdouble);
+                                       } catch (Exception e) {
+                                               o = 
NodeFactory.createLiteral(columnValue);
+                                       }
+                                       
sink.triple(this.profile.createTriple(subject, predicate,
+                                                       o, rowNum, col));
+                               }
+
+                       }
+                       rowNum++;
+               }
+               sink.finish();
+
+       }
+
+       public static String toSafeLocalname(String raw) {
+               String ret = raw.trim();
+               return encodeURIComponent(ret);
+               
+       }
+       
+       public static String encodeURIComponent(String s) {
+           return IRILib.encodeUriComponent(s);
+       }
+       
+       public static Node caculateSubject(int rowNum, String filename){
+               Node subject = NodeFactory.createAnon();
+//             String uri = IRIResolver.resolveString(filename) + "#Row_" + 
rowNum; 
+//             Node subject =  NodeFactory.createURI(uri);
+               return subject;
+       }
+       
+       
+       
+       
+    private static class ReaderRIOTFactoryCSV implements ReaderRIOTFactory
+    {
+        @Override
+        public ReaderRIOT create(Lang lang) {
+            return new ReaderRIOTLangCSV(lang) ;
+        }
+    }
+
+    private static class ReaderRIOTLangCSV implements ReaderRIOT
+    {
+        private final Lang lang ;
+        private ErrorHandler errorHandler ; 
+        private ParserProfile parserProfile = null ;
+
+        ReaderRIOTLangCSV(Lang lang) {
+            this.lang = lang ;
+            errorHandler = ErrorHandlerFactory.getDefaultErrorHandler() ;
+        }
+
+        @Override
+        public void read(InputStream in, String baseURI, ContentType ct, 
StreamRDF output, Context context) {
+            if ( lang == CSV){
+               LangRIOT parser = new LangCSV (in, baseURI, baseURI, 
ErrorHandlerFactory.getDefaultErrorHandler(),  output);
+                if ( parserProfile != null )
+                    parser.setProfile(parserProfile);
+                if ( errorHandler != null )
+                    parser.getProfile().setHandler(errorHandler) ;
+                parser.parse() ;
+            } else {
+               throw new IllegalArgumentException("The Lang must be 'CSV'!");
+            }
+
+        }
+
+        @Override
+        public void read(Reader in, String baseURI, ContentType ct, StreamRDF 
output, Context context) {
+               if ( lang == CSV){
+                       LangRIOT parser = new LangCSV (in, baseURI, baseURI, 
ErrorHandlerFactory.getDefaultErrorHandler(),  output);
+                if ( parserProfile != null )
+                    parser.setProfile(parserProfile);
+                if ( errorHandler != null )
+                    parser.getProfile().setHandler(errorHandler) ;
+                       parser.parse() ;
+               } else {
+               throw new IllegalArgumentException("The Lang must be 'CSV'!");
+            }
+        }
+
+        @Override public ErrorHandler getErrorHandler()                     { 
return errorHandler ; }
+        @Override public void setErrorHandler(ErrorHandler errorHandler)    { 
this.errorHandler = errorHandler ; }
+
+        @Override public ParserProfile getParserProfile()                   { 
return parserProfile ; } 
+        @Override public void setParserProfile(ParserProfile parserProfile) { 
this.parserProfile = parserProfile ; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/74c4bd06/src/main/java/org/apache/jena/propertytable/util/IRILib.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/jena/propertytable/util/IRILib.java 
b/src/main/java/org/apache/jena/propertytable/util/IRILib.java
new file mode 100644
index 0000000..7df9b7f
--- /dev/null
+++ b/src/main/java/org/apache/jena/propertytable/util/IRILib.java
@@ -0,0 +1,262 @@
+/*
+ * 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.jena.propertytable.util;
+
+import java.io.File ;
+import java.io.IOException ;
+
+import org.apache.jena.atlas.AtlasException ;
+import org.apache.jena.atlas.lib.Chars ;
+import org.apache.jena.atlas.lib.StrUtils ;
+import org.apache.jena.riot.SysRIOT ;
+
+/** 
+ * Operations related to IRIs 
+ * Add '£', based on org.apache.jena.riot.system.IRILib
+ */
+public class IRILib
+{
+    // http://www.w3.org/TR/xpath-functions/#func-encode-for-uri
+    // Encodes delimiters.
+    
+    /* RFC 3986
+     * 
+     * unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
+     * gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+     * sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
+                    / "*" / "+" / "," / ";" / "="
+     */
+    
+    private static char uri_reserved[] = 
+    { 
+      '!', '*', '"', '\'', '(', ')', ';', ':', '@', '&', 
+      '=', '+', '$', ',', '/', '?', '%', '#', '[', ']'} ;
+
+    // No allowed in URIs
+    private static char uri_non_chars[] = { '<', '>', '{', '}', '|', '\\', 
'`', '^', ' ',  '\n', '\r', '\t', '£' } ;
+    
+    // RFC 2396
+    //private static char uri_unwise[]    = { '{' , '}', '|', '\\', '^', '[', 
']', '`' } ;
+
+
+    private static char[] charsComponent =
+    // reserved, + non-chars + nasties.
+    { '!', '*', '"', '\'', '(', ')', ';', ':', '@', '&', 
+      '=', '+', '$', ',', '/', '?', '%', '#', '[', ']',
+      '{', '}', '|', '\\', '`', '^',
+      ' ', '<', '>', '\n', '\r', '\t', '£' } ;
+    
+    private static char[] charsFilename =
+        // reserved, + non-chars + nasties.
+        // Leave : (Windows drive charcater) and / (separator) alone
+        // include SPC and ~
+        { '!', '*', '"', '\'', '(', ')', ';', /*':',*/ '@', '&', 
+          '=', '+', '$', ',', /*'/',*/ '?', '%', '#', '[', ']',
+          '{', '}', '|', '\\', '`', '^',
+          ' ', '<', '>', '\n', '\r', '\t',
+          '~'} ;
+
+    private static char[] charsPath =  
+    {
+        // Reserved except leave the separators alone. 
+        // Leave the path separator alone.
+        // Leave the drive separator alone.
+        '!', '*', '"', '\'', '(', ')', ';', /*':',*/ '@', '&',
+        '=', '+', '$', ',', /*'/',*/ '?', '%', '#', '[', ']',
+        '{', '}', '|', '\\', '`', '^',
+        // Other junk 
+        ' ', '<', '>', '\n', '\r', '\t' } ;
+
+    // The initializers must have run.
+    static final String cwd ; 
+    static final String cwdURL ;
+    
+    // Current directory, with trailing "/"
+    // This matters for resolution.
+    static { 
+        String x = new File(".").getAbsolutePath() ;
+        x = x.substring(0, x.length()-1) ;
+        cwd = x ;
+        cwdURL = plainFilenameToURL(cwd) ;
+    }
+    
+    // See also IRIResolver
+    /** Return a string that is an IRI for the filename.*/
+    public static String fileToIRI(File f)
+    {
+        return filenameToIRI(f.getAbsolutePath()) ;
+    }
+    
+    /** Create a string that is a IRI for the filename.
+     *  The file name may already have file:.
+     *  The file name may be relative. 
+     *  Encode using the rules for a path (e.g. ':' and'/' do not get encoded)
+     */
+    public static String filenameToIRI(String fn)
+    {
+        if ( fn == null ) return cwdURL ;
+        
+        if ( fn.length() == 0 ) return cwdURL ;
+        
+        if ( fn.startsWith("file:") )
+            return normalizeFilenameURI(fn) ;
+        return plainFilenameToURL(fn) ;
+    }
+    
+    /** Convert an IRI to a filename */
+    public static String IRIToFilename(String iri)
+    {
+        if ( ! iri.startsWith("file:") )
+            throw new AtlasException("Not a file: URI: "+iri) ; 
+        
+        String fn ;
+        if ( iri.startsWith("file:///") )
+            fn = iri.substring("file://".length()) ;
+        else
+            fn = iri.substring("file:".length()) ;
+        return decode(fn) ;
+    }
+    
+    /** Convert a plain file name (no file:) to a file: URL */
+    private static String plainFilenameToURL(String fn)
+    {
+        // No "file:"
+        // Make Absolute filename.
+        boolean trailingSlash = fn.endsWith("/") ;
+        File file = new File(fn) ;
+        
+        try { fn = file.getCanonicalPath() ; }
+        catch (IOException e) { fn = file.getAbsolutePath() ; }
+        
+        if ( trailingSlash && ! fn.endsWith("/") )
+            fn = fn + "/" ;
+        
+        if ( SysRIOT.isWindows )
+        {
+            // C:\ => file:///C:/... 
+            if ( fn.length() >= 2 && fn.charAt(1) == ':' )
+                // Windows drive letter - already absolute path.
+                // Make "URI" absolute path
+                fn = "/"+fn ;
+            // Convert \ to /
+            // Maybe should do this on all platforms? i.e consistency.
+            fn = fn.replace('\\', '/' ) ;
+        }
+        
+        fn = encodeFileURL(fn) ;
+        return "file://"+fn ;
+    }
+    
+    
+    /** Sanitize a "file:" URL. Must start "file:" */
+    private static String normalizeFilenameURI(String fn)
+    {
+        if ( ! fn.startsWith("file:/") )
+        {
+            // Relative path.
+            String fn2 = fn.substring("file:".length()) ;
+            return plainFilenameToURL(fn2) ;
+        }
+        
+        // Starts file:///
+        if ( fn.startsWith("file:///") )
+            // Assume it's good as return as-is.
+            return fn ;
+
+        if ( fn.startsWith("file://") )
+        {
+            String fn2 = fn.substring("file:/".length()) ;  // Leave one "/"
+            return plainFilenameToURL(fn2) ;
+        }
+
+        // Must be file:/
+        String fn2 = fn.substring("file:".length()) ;
+        return plainFilenameToURL(fn2) ;
+    }
+
+    /** Encode using the rules for a component (e.g. ':' and '/' get encoded) 
+     * Does not encode non-ASCII characters 
+     */
+    public static String encodeUriComponent(String string)
+    {
+        String encStr = StrUtils.encodeHex(string,'%', charsComponent) ;
+        return encStr ;
+    }
+
+    /** Encode using the rules for a file: URL.  
+     *  Does not encode non-ASCII characters
+     */
+    public static String encodeFileURL(String string)
+    {
+        String encStr = StrUtils.encodeHex(string,'%', charsFilename) ;
+        return encStr ;
+    }
+
+    /** Encode using the rules for a path (e.g. ':' and '/' do not get 
encoded) */
+    public static String encodeUriPath(String uri)
+    {
+        // Not perfect.
+        // Encode path.
+        // %-encode chars.
+        uri = StrUtils.encodeHex(uri, '%', charsPath) ;
+        return uri ;
+    }
+
+    public static String decode(String string)
+    {
+        return StrUtils.decodeHex(string, '%') ;
+    }
+
+    public static String encodeNonASCII(String string)
+    {
+        if ( ! containsNonASCII(string) )
+            return string ;
+        
+        byte[] bytes = StrUtils.asUTF8bytes(string) ;
+        StringBuilder sw = new StringBuilder() ;
+        for ( byte b : bytes )
+        {
+            // Signed bytes ...
+            if ( b > 0 )
+            {
+                sw.append( (char) b );
+                continue;
+            }
+
+            int hi = ( b & 0xF0 ) >> 4;
+            int lo = b & 0xF;
+            sw.append( '%' );
+            sw.append( Chars.hexDigitsUC[hi] );
+            sw.append( Chars.hexDigitsUC[lo] );
+        }
+        return sw.toString() ;
+    }
+
+    public static boolean containsNonASCII(String string)
+    {
+        boolean clean = true ;
+        for ( int i = 0 ; i < string.length() ; i++ )
+        {
+            char ch = string.charAt(i) ;
+            if ( ch >= 127 )
+                return true;
+        }
+        return false ;
+    } 
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/74c4bd06/src/test/java/org/apache/jena/propertytable/TS_PropertyTable.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/jena/propertytable/TS_PropertyTable.java 
b/src/test/java/org/apache/jena/propertytable/TS_PropertyTable.java
index 9c916e9..084365d 100644
--- a/src/test/java/org/apache/jena/propertytable/TS_PropertyTable.java
+++ b/src/test/java/org/apache/jena/propertytable/TS_PropertyTable.java
@@ -18,11 +18,12 @@
 
 package org.apache.jena.propertytable;
 
-import org.apache.jena.propertytable.impl.GraphCSVTest;
+import org.apache.jena.propertytable.graph.GraphCSVTest;
 import org.apache.jena.propertytable.impl.PropertyTableArrayImplTest;
 import org.apache.jena.propertytable.impl.PropertyTableBuilderForArrayImplTest;
 import 
org.apache.jena.propertytable.impl.PropertyTableBuilderForHashMapImplTest;
 import org.apache.jena.propertytable.impl.PropertyTableHashMapImplTest;
+import org.apache.jena.propertytable.lang.TestLangCSV;
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
 
@@ -34,6 +35,7 @@ import org.junit.runners.Suite;
        GraphCSVTest.class,
        PropertyTableBuilderForArrayImplTest.class,
        PropertyTableBuilderForHashMapImplTest.class,
+       TestLangCSV.class
 })
 public class TS_PropertyTable {
 

http://git-wip-us.apache.org/repos/asf/jena/blob/74c4bd06/src/test/java/org/apache/jena/propertytable/graph/GraphCSVTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/jena/propertytable/graph/GraphCSVTest.java 
b/src/test/java/org/apache/jena/propertytable/graph/GraphCSVTest.java
new file mode 100644
index 0000000..d6b0c26
--- /dev/null
+++ b/src/test/java/org/apache/jena/propertytable/graph/GraphCSVTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.jena.propertytable.graph;
+
+import org.apache.jena.propertytable.graph.GraphCSV;
+import org.apache.jena.propertytable.lang.LangCSV;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.hp.hpl.jena.query.ARQ;
+import com.hp.hpl.jena.query.Query;
+import com.hp.hpl.jena.query.QueryExecution;
+import com.hp.hpl.jena.query.QueryExecutionFactory;
+import com.hp.hpl.jena.query.QueryFactory;
+import com.hp.hpl.jena.query.QuerySolution;
+import com.hp.hpl.jena.query.ResultSet;
+import com.hp.hpl.jena.rdf.model.Model;
+import com.hp.hpl.jena.rdf.model.ModelFactory;
+import com.hp.hpl.jena.sparql.engine.main.StageBuilder;
+import com.hp.hpl.jena.sparql.engine.main.StageGenerator;
+
+public class GraphCSVTest extends Assert {
+       
+       @BeforeClass
+       public static void init(){
+               LangCSV.register();
+       }
+       
+       @Test
+       public void testGraphCSV() throws Exception {
+               //String file = 
"src/test/resources/HEFCE_organogram_senior_data_31032011.csv";test.csv
+               String file = "src/test/resources/test.csv";
+               
+               Model csv = ModelFactory.createModelForGraph(new 
GraphCSV(file));
+               assertEquals(12, csv.size());
+
+               Query query = QueryFactory
+                               .create("PREFIX : 
<src/test/resources/test.csv#> SELECT ?townName ?pop {?x :Town ?townName ; 
:Population ?pop ; :Predicate%20With%20Space 'PredicateWithSpace2' . 
FILTER(?pop > 500000)}");
+               
+               QueryExecution qexec = QueryExecutionFactory.create(query, csv);
+               ResultSet results = qexec.execSelect();
+               
+               assertTrue(results.hasNext());
+               QuerySolution soln = results.nextSolution();
+               assertEquals( "Northville", 
soln.getLiteral("townName").getString());
+               assertTrue( 654000 == soln.getLiteral("pop").getInt());
+               
+               assertFalse(results.hasNext());
+       }
+       
+       @Test 
+       public void stageGeneratorTest() throws Exception{
+               wireIntoExecution();
+               testGraphCSV();
+       }
+       
+    private static void wireIntoExecution() {
+        StageGenerator orig = 
(StageGenerator)ARQ.getContext().get(ARQ.stageGenerator) ;
+        StageGenerator stageGenerator = new StageGeneratorPropertyTable(orig) ;
+        StageBuilder.setGenerator(ARQ.getContext(), stageGenerator) ;
+    }
+       
+       //http://www.w3.org/TR/csvw-ucr/#UC-OrganogramData
+       //2.4 Use Case #4 - Publication of public sector roles and salaries
+       @Test
+       public void testUseCase4(){
+               String file = 
"src/test/resources/HEFCE_organogram_senior_data_31032011.csv";
+               
+               Model csv = ModelFactory.createModelForGraph(new 
GraphCSV(file));
+               assertEquals(72, csv.size());
+
+               Query query = QueryFactory
+                               .create("PREFIX : 
<src/test/resources/HEFCE_organogram_senior_data_31032011.csv#> SELECT ?name 
?unit {?x :Name ?name ; :Unit ?unit ; :Actual%20Pay%20Floor%20%28%A3%29 ?floor 
; :Actual%20Pay%20Ceiling%20%28%A3%29 ?ceiling . FILTER(?floor > 100000 && 
?ceiling <120000 )}");
+               
+               QueryExecution qexec = QueryExecutionFactory.create(query, csv);
+               ResultSet results = qexec.execSelect();
+               
+               assertTrue(results.hasNext());
+               QuerySolution soln = results.nextSolution();
+               assertEquals( "David Sweeney", 
soln.getLiteral("name").getString());
+               assertEquals( "Research, Innovation and Skills", 
soln.getLiteral("unit").getString());
+               
+               assertFalse(results.hasNext());
+       }
+       
+       
+       //http://www.w3.org/TR/csvw-ucr/#UC-JournalArticleSearch
+       //2.6 Use Case #6 - Journal Article Solr Search Results
+       @Test
+       public void testUseCase6(){
+               String file = "src/test/resources/PLOSone-search-results.csv";
+               
+               Model csv = ModelFactory.createModelForGraph(new 
GraphCSV(file));
+               assertEquals(30, csv.size());
+
+               Query query = QueryFactory
+                               .create("PREFIX : 
<src/test/resources/PLOSone-search-results.csv#> SELECT ?author {?x :author 
?author ; :doi '10.1371/journal.pone.0095156' }");
+               
+               QueryExecution qexec = QueryExecutionFactory.create(query, csv);
+               ResultSet results = qexec.execSelect();
+               
+               assertTrue(results.hasNext());
+               QuerySolution soln = results.nextSolution();
+               assertEquals( "Oshrat Raz,Dorit L Lev,Alexander Battler,Eli I 
Lev", soln.getLiteral("author").getString());
+               
+               assertFalse(results.hasNext());
+       }
+       
+       //http://www.w3.org/TR/csvw-ucr/#UC-PaloAltoTreeData
+       //2.11 Use Case #11 - City of Palo Alto Tree Data
+       @Test
+       public void testUseCase11(){
+               String file = "src/test/resources/Palo_Alto_Trees.csv";
+               
+               Model csv = ModelFactory.createModelForGraph(new 
GraphCSV(file));
+               assertEquals(199, csv.size());
+
+               Query query = QueryFactory
+                               .create("PREFIX : 
<src/test/resources/Palo_Alto_Trees.csv#> SELECT ?longitude ?latitude {?x 
:Longitude ?longitude ; :Latitude ?latitude ; :Distance%20from%20Property 
?distance . FILTER(?distance > 50 )}");
+               
+               QueryExecution qexec = QueryExecutionFactory.create(query, csv);
+               ResultSet results = qexec.execSelect();
+               
+               assertTrue(results.hasNext());
+               QuerySolution soln = results.nextSolution();
+               assertEquals( -122.1566921, 
soln.getLiteral("longitude").getDouble(), 0);
+               assertEquals( 37.4408948, 
soln.getLiteral("latitude").getDouble(), 0);
+               
+               assertFalse(results.hasNext());
+       }
+
+}

Reply via email to