You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2012/01/29 18:30:44 UTC

svn commit: r1237373 - in /incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader: ./ HttpOp2.java RDFReaderFactoryRIOT.java RDFReaderRIOT.java Reader.java Registry2.java TypedStreamHttp.java WebReader2.java

Author: andy
Date: Sun Jan 29 17:30:44 2012
New Revision: 1237373

URL: http://svn.apache.org/viewvc?rev=1237373&view=rev
Log:
Experimental new reader architecture for RIOT.

Added:
    incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/
    incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/HttpOp2.java
    incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/RDFReaderFactoryRIOT.java
    incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/RDFReaderRIOT.java
    incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/Reader.java
    incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/Registry2.java
    incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/TypedStreamHttp.java
    incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/WebReader2.java

Added: incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/HttpOp2.java
URL: http://svn.apache.org/viewvc/incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/HttpOp2.java?rev=1237373&view=auto
==============================================================================
--- incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/HttpOp2.java (added)
+++ incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/HttpOp2.java Sun Jan 29 17:30:44 2012
@@ -0,0 +1,115 @@
+/**
+ * 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 riot.reader;
+
+import static java.lang.String.format ;
+
+import java.io.IOException ;
+import java.util.concurrent.atomic.AtomicLong ;
+
+import org.apache.http.HttpEntity ;
+import org.apache.http.HttpResponse ;
+import org.apache.http.StatusLine ;
+import org.apache.http.client.HttpClient ;
+import org.apache.http.client.methods.HttpGet ;
+import org.apache.http.impl.client.DefaultHttpClient ;
+import org.openjena.atlas.io.IO ;
+import org.openjena.atlas.web.HttpException ;
+import org.openjena.atlas.web.MediaType ;
+import org.openjena.riot.web.HttpNames ;
+
+public class HttpOp2
+{
+
+    static private AtomicLong counter = new AtomicLong(0) ;
+
+    public static TypedStreamHttp execHttpGet(String url, String acceptHeader)
+    {
+        try {
+            long id = counter.incrementAndGet() ;
+            String requestURI = determineRequestURI(url) ;
+            String baseIRI = determineBaseIRI(requestURI) ;
+    
+            HttpGet httpget = new HttpGet(requestURI);
+            if ( WebReader2.log.isDebugEnabled() )
+                WebReader2.log.debug(format("[%d] %s %s",id ,httpget.getMethod(),httpget.getURI().toString())) ;
+            // Accept
+            if ( acceptHeader != null )
+                httpget.addHeader(HttpNames.hAccept, acceptHeader) ;
+            
+            // Execute
+            HttpClient httpclient = new DefaultHttpClient();        // Pool?
+            HttpResponse response = httpclient.execute(httpget) ;
+            
+            // Response
+            StatusLine statusLine = response.getStatusLine() ;
+            if ( statusLine.getStatusCode() >= 404 )
+            {
+                WebReader2.log.debug(format("[%d] %s %s",id, statusLine.getStatusCode(), statusLine.getReasonPhrase())) ;
+                return null ;
+            }
+            if ( statusLine.getStatusCode() >= 400 )
+            {
+                WebReader2.log.debug(format("[%d] %s %s",id, statusLine.getStatusCode(), statusLine.getReasonPhrase())) ;
+                throw new HttpException(statusLine.getStatusCode()+" "+statusLine.getReasonPhrase()) ;
+            }
+    
+            HttpEntity entity = response.getEntity() ;
+            if ( entity == null )
+            {
+                
+            }
+                
+            MediaType mt = new MediaType(entity.getContentType().getValue()) ;
+            if ( WebReader2.log.isDebugEnabled() )
+                WebReader2.log.debug(format("[%d] %d %s :: %s",id, statusLine.getStatusCode(), statusLine.getReasonPhrase() , mt)) ;
+                
+            return new TypedStreamHttp(entity.getContent(), mt,
+                                       httpclient.getConnectionManager()) ;
+        }
+        catch (IOException ex) { IO.exception(ex) ; return null ; }
+    }
+
+    private static String determineRequestURI(String url)
+    {
+        String requestURI = url ;
+        if ( requestURI.contains("#") )
+        {
+            // No frag ids.
+            int i = requestURI.indexOf('#') ;
+            requestURI = requestURI.substring(0,i) ;
+        }
+        return requestURI ;
+    }
+
+    private static String determineBaseIRI(String requestURI)
+    {
+        // Technically wrong, but including the query string is "unhelpful"
+        String baseIRI = requestURI ;
+        if ( requestURI.contains("?") )
+        {
+            // No frag ids.
+            int i = requestURI.indexOf('?') ;
+            baseIRI = requestURI.substring(0,i) ;
+        }
+        return baseIRI ;
+    }
+
+}
+

Added: incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/RDFReaderFactoryRIOT.java
URL: http://svn.apache.org/viewvc/incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/RDFReaderFactoryRIOT.java?rev=1237373&view=auto
==============================================================================
--- incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/RDFReaderFactoryRIOT.java (added)
+++ incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/RDFReaderFactoryRIOT.java Sun Jan 29 17:30:44 2012
@@ -0,0 +1,49 @@
+/**
+ * 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 riot.reader;
+
+import com.hp.hpl.jena.rdf.model.RDFReader ;
+import com.hp.hpl.jena.rdf.model.RDFReaderF ;
+
+public class RDFReaderFactoryRIOT implements RDFReaderF
+{
+
+    // Map language to base.
+    // .. crudely ... 
+    
+    @Override
+    public RDFReader getReader()
+    {
+        return null ;
+    }
+
+    @Override
+    public RDFReader getReader(String lang)
+    {
+        return new RDFReaderRIOT(lang) ; 
+    }
+
+    @Override
+    public String setReaderClassName(String lang, String className)
+    {
+        return null ;
+    }
+
+}
+

Added: incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/RDFReaderRIOT.java
URL: http://svn.apache.org/viewvc/incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/RDFReaderRIOT.java?rev=1237373&view=auto
==============================================================================
--- incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/RDFReaderRIOT.java (added)
+++ incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/RDFReaderRIOT.java Sun Jan 29 17:30:44 2012
@@ -0,0 +1,79 @@
+/**
+ * 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 riot.reader;
+
+import java.io.InputStream ;
+import java.io.Reader ;
+import java.util.Locale ;
+
+import org.openjena.atlas.lib.NotImplemented ;
+
+import com.hp.hpl.jena.rdf.model.Model ;
+import com.hp.hpl.jena.rdf.model.RDFErrorHandler ;
+import com.hp.hpl.jena.rdf.model.RDFReader ;
+import com.hp.hpl.jena.rdf.model.impl.RDFDefaultErrorHandler ;
+import com.hp.hpl.jena.sparql.util.Context ;
+import com.hp.hpl.jena.sparql.util.Symbol ;
+
+/** Adapter from Jena2 original style adapter to RIOT reader. */ 
+public class RDFReaderRIOT implements RDFReader
+{
+    // See also JenaReaderBase, JenaReaderRiot
+
+    private final String base ; // This will be per 
+    Context context = new Context() ;
+    
+    RDFErrorHandler errorHandler = new RDFDefaultErrorHandler();
+    
+    public RDFReaderRIOT(String lang)
+    {
+        base = "org.apache.jena.LANG."+lang.toLowerCase(Locale.US) ;
+    }
+
+    @Override
+    public void read(Model model, Reader r, String base)
+    { throw new NotImplemented() ; }
+
+    @Override
+    public void read(Model model, InputStream r, String base)
+    { throw new NotImplemented() ; }
+    
+    @Override
+    public void read(Model model, String url)
+    {
+        WebReader2.read(model, url) ;
+    }
+
+    @Override
+    public Object setProperty(String propName, Object propValue)
+    {
+        Symbol sym = Symbol.create(base+propName) ;
+        Object oldObj = context.get(sym) ;
+        return oldObj ;
+    }
+    
+    @Override
+    public RDFErrorHandler setErrorHandler(RDFErrorHandler errHandler)
+    {
+        RDFErrorHandler old = errorHandler ;
+        errorHandler = errHandler ;
+        return old ;
+    }
+}
+

Added: incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/Reader.java
URL: http://svn.apache.org/viewvc/incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/Reader.java?rev=1237373&view=auto
==============================================================================
--- incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/Reader.java (added)
+++ incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/Reader.java Sun Jan 29 17:30:44 2012
@@ -0,0 +1,33 @@
+/**
+ * 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 riot.reader;
+
+import java.io.InputStream ;
+
+import org.openjena.atlas.lib.Sink ;
+import org.openjena.riot.ContentType ;
+
+import com.hp.hpl.jena.sparql.util.Context ;
+
+/** Interface to parsing processes that take an input stream and emit T items */
+
+public interface Reader<T>
+{
+    public void read(InputStream in, String baseURI, ContentType ct, Sink<T> sink, Context context) ;
+}

Added: incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/Registry2.java
URL: http://svn.apache.org/viewvc/incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/Registry2.java?rev=1237373&view=auto
==============================================================================
--- incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/Registry2.java (added)
+++ incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/Registry2.java Sun Jan 29 17:30:44 2012
@@ -0,0 +1,42 @@
+/**
+ * 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 riot.reader;
+
+import java.util.HashMap ;
+import java.util.Iterator ;
+import java.util.Map ;
+
+// ----- Copied from Fuseki migrate
+public class Registry2<T>
+{
+    protected Map<String, T> registry = new HashMap<String, T>() ;
+    
+    public Registry2() {}
+    
+    public void put(String key, T value) { registry.put(key, value) ; }
+    
+    public T get(String key) { return registry.get(key) ; }
+    
+    public boolean isRegistered(String key) { return registry.containsKey(key) ; }
+    public void remove(String key) { registry.remove(key) ; } 
+    public Iterator<String> keys() { return registry.keySet().iterator() ; }
+    
+    public int size() { return registry.size() ; }
+    public boolean isEmpty() { return registry.isEmpty() ; }
+}

Added: incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/TypedStreamHttp.java
URL: http://svn.apache.org/viewvc/incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/TypedStreamHttp.java?rev=1237373&view=auto
==============================================================================
--- incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/TypedStreamHttp.java (added)
+++ incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/TypedStreamHttp.java Sun Jan 29 17:30:44 2012
@@ -0,0 +1,46 @@
+/**
+ * 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 riot.reader;
+
+import java.io.InputStream ;
+
+import org.apache.http.conn.ClientConnectionManager ;
+import org.openjena.atlas.web.MediaType ;
+import org.openjena.atlas.web.TypedStream ;
+
+/** Type streams for HTTP connections - includes Apache HTTP client specific cleanup */
+public class TypedStreamHttp extends TypedStream 
+{
+    private ClientConnectionManager connectMgr ;
+
+    TypedStreamHttp(InputStream input, MediaType mt, ClientConnectionManager connectMgr)
+    {
+        super(input, mt.getContentType(), mt.getCharset()) ;
+        this.connectMgr = connectMgr ;
+    }
+    
+    @Override
+    public void close()
+    {
+        super.close() ;
+        if ( connectMgr != null )
+            connectMgr.shutdown() ;
+    }
+    
+}

Added: incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/WebReader2.java
URL: http://svn.apache.org/viewvc/incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/WebReader2.java?rev=1237373&view=auto
==============================================================================
--- incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/WebReader2.java (added)
+++ incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/reader/WebReader2.java Sun Jan 29 17:30:44 2012
@@ -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 riot.reader;
+
+import java.io.InputStream ;
+
+import org.openjena.atlas.lib.Sink ;
+import org.openjena.atlas.logging.Log ;
+import org.openjena.atlas.web.TypedStream ;
+import org.openjena.riot.ContentType ;
+import org.openjena.riot.Lang ;
+import org.openjena.riot.RiotLoader ;
+import org.openjena.riot.WebContent ;
+import org.openjena.riot.lang.SinkTriplesToGraph ;
+import org.slf4j.Logger ;
+import org.slf4j.LoggerFactory ;
+
+import com.hp.hpl.jena.graph.Graph ;
+import com.hp.hpl.jena.graph.Triple ;
+import com.hp.hpl.jena.rdf.model.Model ;
+import com.hp.hpl.jena.rdf.model.ModelFactory ;
+import com.hp.hpl.jena.sparql.util.Context ;
+import com.hp.hpl.jena.util.FileManager ;
+
+/** General purpose reader framework.
+ */
+/*
+ *  Design notes
+ *    There are functions (static methods) for reading various kinds of "thing"
+ *    streams of triples or quads, result sets, (other?)
+ *    
+ *    The lifecycle of a "read" action is:
+ *       open -> TypeStream
+ *       process
+ *       ts.close
+ *       
+ *  Open issues:
+ *    How to make this extensible - people want add readers (e.g. GRDDL, RDFa, 
+ *    microdata, microsformats).  But we don't want to require
+ *    Jena needing to supply each and every kind of parser as a core
+ *    feature.
+ *    
+ * To Do
+ *   Sort out ContentType vs MediaType
+ *   Sort out contants and naming
+ *   Should this be "Lang" driven - make Lang extensible (use Symbol).
+ *   
+ * FileManger
+ *   remove cache (worng place) 
+ *   openTypedStream
+ *   Locators to do the remapping?  No - nice that it's orthogical.
+ */
+public class WebReader2
+{
+    // **** Additional to, and upgrade of, riot.WebReader
+    static Logger log = LoggerFactory.getLogger(WebReader2.class) ;
+
+    public static void main(String ... argv)
+    {
+        Log.enable(WebReader2.class) ;
+        Model m = ModelFactory.createDefaultModel() ;
+        read(m, "http://localhost:3030/books.ttl", WebContent.contentTypeTurtle, null) ;
+        //read(m, "file:data.ttl", WebContent.contentTypeTurtle, null) ;
+        //SSE.write(m) ;
+        System.out.println("triples = "+m.size()) ;
+    }
+    
+    //    interface ReaderFactory<T> { Reader<T> create() ; }
+    // ----- 
+    static public Registry2<Reader<Triple>> registryGraphReaders = new Registry2<Reader<Triple>>() ;
+
+    // >>>> **** Setup
+    // Lang is an enum and hence closed.
+    //   lang -> open-ended?
+    // Constants - all needs sorting out!
+    // Order dependent choices? Chains of "try me"?
+    static {
+        register(WebContent.contentTypeTurtle, new ReaderLangTriple(Lang.TURTLE)) ;
+        register(WebContent.contentTypeNTriples, new ReaderLangTriple(Lang.NTRIPLES)) ;
+        register(WebContent.contentTypeRDFXML, new ReaderLangTriple(Lang.RDFXML)) ;
+        register(WebContent.contentTypeRDFJSON, new ReaderLangTriple(Lang.RDFJSON)) ;
+        //register("*", null) ;
+    }
+    
+    public static void register(String contentType, Reader<Triple> reader)
+    {
+        // Check name?
+        registryGraphReaders.put(contentType, reader) ;
+    }
+    
+    // <<<< **** Setup
+
+    // **** See also HttpResponseLib (handler-dispatch style)
+    //      Merge here, and delete 
+    //      Specific to HTTP.
+    //      Can we use it's generalization for result set?
+    
+    //      How to have a registry --  
+    //         partly, WebContent.contentTypeToLang(in.getContentType()) ;
+    //         but why not content type -> reader?
+    
+    // Sort out riot.ContentType and riot.web.MediaType
+    // ContentType - little used but better?
+    
+    /** Read triples into a Model from the given location.
+     */
+    public static void read(Model m, String uri)                    { read(m, uri, null, null) ; }
+    
+    /** Read triples into a Model from the given location, with a ghint of the language (MIME type) */
+    public static void read(Model m, String uri, String hintLang)   { read(m, uri, hintLang, null) ; }
+    
+    /** Read triples into a Model from the given location, with some parameters for the reader */ 
+    public static void read(Model m, String uri, Context context)   { read(m, uri, null, context) ; }
+    
+    /** Read triples into a Model from the given location, with hint of langauge and the with some parameters for the reader 
+    *  Throws XYZ if there is no location to read from, and the model is unchanged.
+    *  Throws parse errors depending on the language and reader.
+    */
+    public static void read(Model m, String uri, String hintLang, Context context)
+    {
+        // return some sort of otehr all status - boolean?
+        TypedStream in = open(uri) ;
+        if ( in == null )
+            return ;
+        process(m, uri, in, hintLang, context) ;
+        in.close() ;
+    }
+
+    // --> WebContent, basic formats (not RDFa orreturn null ; other emvbedded data format).
+    static String acceptTriples = "text/turtle,application/rdf+xml;q=0.9,application/xml;q=0.8,*/*;q=0.5" ; 
+
+    private static TypedStream open(String filenameOrURI)
+    {
+        // Testing.
+        // faked up file manager.
+        FileManager fMgr = new FileManager() ;
+        fMgr.addLocatorFile() ;
+        fMgr.addLocatorClassLoader(Thread.currentThread().getContextClassLoader()) ;
+        
+        InputStream in = fMgr.open(filenameOrURI) ;
+            
+        if ( in != null )
+        {
+            if ( log.isDebugEnabled() )
+                //log.debug("Found: "+filenameOrURI+" ("+loc.getName()+")") ;
+                log.debug("Found: "+filenameOrURI) ;
+            TypedStream ts = new TypedStream(in, null) ;
+            return ts ;
+        }
+        // Not found - try the web!
+        String target = fMgr.mapURI(filenameOrURI) ;
+        
+        if ( target.startsWith("http://") || target.startsWith("https://"))
+            return HttpOp2.execHttpGet(filenameOrURI, acceptTriples) ;
+        return null ;
+    }
+    
+//     static class LocatorHTTP implements Locator
+//     {
+//        @Override
+//        public com.hp.hpl.jena.util.TypedStream open(String filenameOrURI)
+//        {
+//            return HttpOp2.execHttpGet(filenameOrURI, acceptTriples) ;
+//        }
+//
+//        @Override
+//        public String getName()
+//        {
+//            return "HTTP Locator" ;
+//        }
+//     }
+    
+    // ----- 
+    // Readers are algorithms and must be stateless (or create a per run instance of something)
+    // and may be called concurrency for different threads.
+    // The Context object gives the per-run configuration.  
+    
+    // Alternative: A two step factory-instance design means
+    // readers can be created and passed around (e,.g. to set specific features)
+    // We could have had two step design - ReaderFactory-ReaderInstance
+    // no - put the bruden on complicated readers, not everyone. 
+    
+    private static void process(Model m, String uri, TypedStream in, String hintLang, Context context)
+    {
+        Graph g = m.getGraph() ;
+        Sink<Triple> sink = new SinkTriplesToGraph(g) ;
+        
+        if ( false )
+        {
+            // Assumes Lang is extensible.
+            boolean isTextPlain = WebContent.contentTypeTextPlain.equals(in.getContentType()) ; 
+            Lang lang1 = Lang.guess(uri) ;
+            Lang lang2 = WebContent.contentTypeToLang(in.getContentType()) ;
+
+            // Tune
+            Lang lang = lang2 ;
+            if ( lang == null || isTextPlain )
+            {
+                lang = lang1 ;
+            }
+
+            RiotLoader.readTriples(in.getInput(), lang, uri, sink) ;
+        }
+        else
+        {
+            // Extensible(?)
+            // Hint?
+            String _ct = null ;
+            if ( in.getMediaType() != null )
+                _ct = WebContent.contentTypeCanonical(in.getContentType()) ;
+            if ( _ct == null )
+                _ct = hintLang ;
+            // Error? ....
+            ContentType ct = ContentType.parse(_ct) ;
+            Reader<Triple> reader = registryGraphReaders.get(_ct) ;
+            reader.read(in.getInput(), uri, ct, sink, context) ;
+        }
+    }
+
+    /** General reader-of-triples for a fixed language */
+    static class ReaderLangTriple implements Reader<Triple>
+    {
+        private final Lang lang ;
+
+        ReaderLangTriple(Lang lang) { this.lang = lang ; }
+        
+        @Override
+        public void read(InputStream in, String baseURI, ContentType ct, Sink<Triple> sink, Context context)
+        {
+            RiotLoader.readTriples(in, lang, baseURI, sink) ;
+        }
+    } 
+
+    
+//    static HttpResponseHandler turtleHandler = new HttpResponseHandler(){
+//        @Override
+//        public void handle(String contentType, String baseIRI, HttpResponse response) throws IOException
+//        {}} ;
+//    
+//    static Map<String, HttpResponseHandler> handlers = new HashMap<>() ;
+//    static {
+//        handlers.put(WebContent.contentTypeTurtle, null ) ;
+//    }
+    
+}
+