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 2014/06/12 17:30:34 UTC

svn commit: r1602204 - in /jena/Experimental/jena-fuseki2: ./ src/main/java/org/apache/jena/fuseki/mgt/ src/main/java/org/apache/jena/fuseki/servlets/

Author: andy
Date: Thu Jun 12 15:30:34 2014
New Revision: 1602204

URL: http://svn.apache.org/r1602204
Log:
Calculate upload statistics. Return in JSON

Added:
    jena/Experimental/jena-fuseki2/D.ttl   (with props)
    jena/Experimental/jena-fuseki2/dwim-upload   (with props)
    jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/UploadDetails.java   (with props)
Modified:
    jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/mgt/ActionDatasets.java
    jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads_RW.java
    jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP_RW.java
    jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/ServletOps.java
    jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/Upload.java

Added: jena/Experimental/jena-fuseki2/D.ttl
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-fuseki2/D.ttl?rev=1602204&view=auto
==============================================================================
Binary file - no diff available.

Propchange: jena/Experimental/jena-fuseki2/D.ttl
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: jena/Experimental/jena-fuseki2/dwim-upload
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-fuseki2/dwim-upload?rev=1602204&view=auto
==============================================================================
--- jena/Experimental/jena-fuseki2/dwim-upload (added)
+++ jena/Experimental/jena-fuseki2/dwim-upload Thu Jun 12 15:30:34 2014
@@ -0,0 +1,31 @@
+#!/bin/bash
+# How to do a file upload in curl
+
+# GSP strict
+U='http://localhost:3030/ds/data?graph=http://example/G'
+# PUT
+## curl --upload-file D.ttl --header 'Content-Type: text/turtle' "$U"
+
+# POST
+curl -XPOST --upload-file D.ttl --header 'Content-Type: text/turtle' "$U"
+
+
+
+# Quads to GSP
+
+## curl -F 'file=@D.ttl' http://localhost:3030/ds/data
+## curl -F 'file=@D.trig' http://localhost:3030/ds/data
+
+# Quads to graph : NGs in data ignored
+# curl -F 'file=@D.trig' 'http://localhost:3030/ds/data?default'
+#curl -F 'file=@D.trig' 'http://localhost:3030/ds/data?graph=http://example/G'
+
+# Dataset
+## curl -F 'file=@D.trig' http://localhost:3030/ds
+
+# Upload service
+## curl -F 'file=@D.trig' -F 'name=http://graph/' 'http://localhost:3030/ds/upload'
+
+
+echo "==== Dataset"
+curl  http://localhost:3030/ds

Propchange: jena/Experimental/jena-fuseki2/dwim-upload
------------------------------------------------------------------------------
    svn:executable = *

Modified: jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/mgt/ActionDatasets.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/mgt/ActionDatasets.java?rev=1602204&r1=1602203&r2=1602204&view=diff
==============================================================================
--- jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/mgt/ActionDatasets.java (original)
+++ jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/mgt/ActionDatasets.java Thu Jun 12 15:30:34 2014
@@ -313,7 +313,7 @@ public class ActionDatasets extends Acti
     }
 
     private void assemblerFromUpload(HttpAction action, StreamRDF dest) {
-        Upload.fileUploadWorker(action, dest, true);
+        Upload.fileUploadWorker(action, dest);
     }
 
     // ---- DELETE

Modified: jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads_RW.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads_RW.java?rev=1602204&r1=1602203&r2=1602204&view=diff
==============================================================================
--- jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads_RW.java (original)
+++ jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads_RW.java Thu Jun 12 15:30:34 2014
@@ -80,7 +80,7 @@ public class REST_Quads_RW extends REST_
         try {
             DatasetGraph dsg = action.getActiveDSG() ;
             StreamRDF dest = StreamRDFLib.dataset(dsg) ;
-            Upload.incomingData(action, dest, false) ;
+            UploadDetails details = Upload.incomingData(action, dest) ;
             action.commit() ;
             ServletOps.success(action) ;
         } catch (RiotException ex) {
@@ -100,10 +100,12 @@ public class REST_Quads_RW extends REST_
         DatasetGraph dsgTmp = DatasetGraphFactory.createMem() ;
         StreamRDF dest = StreamRDFLib.dataset(dsgTmp) ;
 
+        UploadDetails details ;
         try {
-            Upload.incomingData(action, dest, false) ;
+            details = Upload.incomingData(action, dest) ;
         } catch (RiotException ex) {
             ServletOps.errorBadRequest(ex.getMessage()) ;
+            return ;
         }
         // Now insert into dataset
         action.beginWrite() ;

Modified: jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP_RW.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP_RW.java?rev=1602204&r1=1602203&r2=1602204&view=diff
==============================================================================
--- jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP_RW.java (original)
+++ jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP_RW.java Thu Jun 12 15:30:34 2014
@@ -18,13 +18,16 @@
 
 package org.apache.jena.fuseki.servlets;
 
+import static org.apache.jena.riot.WebContent.ctMultipartMixed ;
+import static org.apache.jena.riot.WebContent.matchContentType ;
+import org.apache.jena.atlas.json.JsonValue ;
 import org.apache.jena.atlas.web.ContentType ;
 import org.apache.jena.fuseki.FusekiLib ;
-import org.apache.jena.riot.web.HttpNames ;
+import org.apache.jena.fuseki.servlets.UploadDetails.PreState ;
 import org.apache.jena.riot.RiotException ;
-import static org.apache.jena.riot.WebContent.* ;
 import org.apache.jena.riot.system.StreamRDF ;
 import org.apache.jena.riot.system.StreamRDFLib ;
+import org.apache.jena.riot.web.HttpNames ;
 import org.apache.jena.web.HttpSC ;
 
 import com.hp.hpl.jena.graph.Graph ;
@@ -81,16 +84,20 @@ public class SPARQL_GSP_RW extends SPARQ
             ServletOps.error(HttpSC.UNSUPPORTED_MEDIA_TYPE_415, "multipart/mixed not supported") ;
         }
         
-        boolean existedBefore = false ;
+        UploadDetails details ;
         if ( action.isTransactional() )
-            existedBefore = addDataIntoTxn(action, overwrite) ;
+            details = addDataIntoTxn(action, overwrite) ;
         else
-            existedBefore = addDataIntoNonTxn(action, overwrite) ;
-            
-        if ( existedBefore )
-            ServletOps.successNoContent(action) ;
+            details = addDataIntoNonTxn(action, overwrite) ;
+        
+        // WRONG
+        if ( details.getExistedBefore().equals(PreState.ABSENT) )
+            ServletOps.successCreated(action) ; // Gets lost by 
         else
-            ServletOps.successCreated(action) ;
+            ServletOps.success(action) ; // successNoContent if empty body.
+        
+        JsonValue v = details.detailsJson() ;
+        ServletOps.sendJson(action, v) ;
     }
 
     /** Directly add data in a transaction.
@@ -100,7 +107,7 @@ public class SPARQL_GSP_RW extends SPARQ
      * @param cleanDest Whether to remove data first (true = PUT, false = POST)
      * @return whether the target existed beforehand
      */
-    protected static boolean addDataIntoTxn(HttpAction action, boolean overwrite) {   
+    protected static UploadDetails addDataIntoTxn(HttpAction action, boolean overwrite) {   
         action.beginWrite();
         Target target = determineTarget(action) ;
         boolean existedBefore = false ;
@@ -112,19 +119,20 @@ public class SPARQL_GSP_RW extends SPARQ
             if ( overwrite && existedBefore )
                 clearGraph(target) ;
             StreamRDF sink = StreamRDFLib.graph(g) ;
-            Upload.incomingData(action, sink, true);
+            UploadDetails upload = Upload.incomingData(action, sink);
+            upload.setExistedBefore(existedBefore) ;
             action.commit() ;
-            return existedBefore ;
+            return upload ;
         } catch (RiotException ex) { 
             // Parse error
             action.abort() ;
             ServletOps.errorBadRequest(ex.getMessage()) ;
-            return existedBefore ;
+            return null ;
         } catch (Exception ex) {
             // Something else went wrong.  Backout.
             action.abort() ;
             ServletOps.errorOccurred(ex.getMessage()) ;
-            return existedBefore ;
+            return null ;
         } finally {
             action.endWrite() ;
         }
@@ -139,14 +147,15 @@ public class SPARQL_GSP_RW extends SPARQ
      * @return whether the target existed beforehand.
      */
     
-    protected static boolean addDataIntoNonTxn(HttpAction action, boolean overwrite) {
+    protected static UploadDetails addDataIntoNonTxn(HttpAction action, boolean overwrite) {
         Graph graphTmp = GraphFactory.createGraphMem() ;
         StreamRDF dest = StreamRDFLib.graph(graphTmp) ;
 
-        try { Upload.incomingData(action, dest, true); }
+        UploadDetails details ;
+        try { details = Upload.incomingData(action, dest); }
         catch (RiotException ex) {
             ServletOps.errorBadRequest(ex.getMessage()) ;
-            return false ;
+            return null ;
         }
         // Now insert into dataset
         action.beginWrite() ;
@@ -159,8 +168,9 @@ public class SPARQL_GSP_RW extends SPARQ
             if ( overwrite && existedBefore )
                 clearGraph(target) ;
             FusekiLib.addDataInto(graphTmp, target.dsg, target.graphName) ;
+            details.setExistedBefore(existedBefore) ;
             action.commit() ;
-            return existedBefore ;
+            return details ;
         } catch (Exception ex) {
             // We parsed into a temporary graph so an exception at this point
             // is not because of a parse error.
@@ -168,7 +178,7 @@ public class SPARQL_GSP_RW extends SPARQ
             // but it might and there is no harm safely trying. 
             try { action.abort() ; } catch (Exception ex2) {} 
             ServletOps.errorOccurred(ex.getMessage()) ;
-            return existedBefore ;            
+            return null ;            
         } finally { action.endWrite() ; }
     }
     

Modified: jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/ServletOps.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/ServletOps.java?rev=1602204&r1=1602203&r2=1602204&view=diff
==============================================================================
--- jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/ServletOps.java (original)
+++ jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/ServletOps.java Thu Jun 12 15:30:34 2014
@@ -159,13 +159,23 @@ public class ServletOps {
         response.setHeader(HttpNames.hPragma, "no-cache");
     }
     
-    /** Send a JSON value as a 200 response.  Null objetc means no response body and no content-type headers. */
+    /** Send a JSON value as a 200 response.  Null object means no response body and no content-type headers. */
     public static void sendJsonReponse(HttpAction action, JsonValue v) {
         if ( v == null ) {
             ServletOps.success(action);
+            //ServletOps.successNoContent(action);
             return ;
         }
         
+        ServletOps.success(action);
+        sendJson(action, v) ;
+    }
+
+    /** Send a JSON value as a 200 response.  Null object means no response body and no content-type headers. */
+    public static void sendJson(HttpAction action, JsonValue v) {
+        if ( v == null )
+            return ;
+        
         try {
             HttpServletResponse response = action.response ;
             ServletOutputStream out = response.getOutputStream() ;
@@ -174,10 +184,9 @@ public class ServletOps {
             JSON.write(out, v) ;
             out.println() ; 
             out.flush() ;
-            ServletOps.success(action);
         } catch (IOException ex) { ServletOps.errorOccurred(ex) ; }
     }
-    
+
 
 }
 

Modified: jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/Upload.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/Upload.java?rev=1602204&r1=1602203&r2=1602204&view=diff
==============================================================================
--- jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/Upload.java (original)
+++ jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/Upload.java Thu Jun 12 15:30:34 2014
@@ -20,6 +20,7 @@ package org.apache.jena.fuseki.servlets;
 
 import static java.lang.String.format ;
 import static org.apache.jena.riot.WebContent.ctMultipartFormData ;
+import static org.apache.jena.riot.WebContent.ctTextPlain ;
 import static org.apache.jena.riot.WebContent.matchContentType ;
 
 import java.io.IOException ;
@@ -35,42 +36,45 @@ import org.apache.jena.fuseki.FusekiLib 
 import org.apache.jena.riot.Lang ;
 import org.apache.jena.riot.RDFLanguages ;
 import org.apache.jena.riot.RiotParseException ;
-import static org.apache.jena.riot.WebContent.* ;
 import org.apache.jena.riot.lang.StreamRDFCounting ;
 import org.apache.jena.riot.system.StreamRDF ;
 import org.apache.jena.riot.system.StreamRDFLib ;
 
 public class Upload {
-    public static void incomingData(HttpAction action, StreamRDF dest, boolean isGraph) {
+    public static UploadDetails incomingData(HttpAction action, StreamRDF dest) {
         ContentType ct = FusekiLib.getContentType(action) ;
          
         if ( matchContentType(ctMultipartFormData, ct) ) {
-            fileUploadWorker(action, dest, isGraph) ;
-            return ;
+            return fileUploadWorker(action, dest) ;
         }
         // Single graph (or quads) in body.
         
-        String base = ActionLib.wholeRequestURL(action.request) ; // XXX Actually wrong?!
+        String base = ActionLib.wholeRequestURL(action.request) ;
         Lang lang = RDFLanguages.contentTypeToLang(ct.getContentType()) ;
         if ( lang == null ) {
             ServletOps.errorBadRequest("Unknown content type for triples: " + ct) ;
-            return ;
+            return null ;
         }
         InputStream input = null ;
         try { input = action.request.getInputStream() ; } 
         catch (IOException ex) { IO.exception(ex) ; }
     
         int len = action.request.getContentLength() ;
-        if ( action.verbose ) {
-            if ( len >= 0 )
-                action.log.info(format("[%d]   Body: Content-Length=%d, Content-Type=%s, Charset=%s => %s", action.id, len,
-                                ct.getContentType(), ct.getCharset(), lang.getName())) ;
-            else
-                action.log.info(format("[%d]   Body: Content-Type=%s, Charset=%s => %s", action.id, ct.getContentType(),
-                                ct.getCharset(), lang.getName())) ;
+
+        StreamRDFCounting countingDest = StreamRDFLib.count(dest) ;
+        try {
+            ActionSPARQL.parse(action, countingDest, input, lang, base) ;
+            UploadDetails details = new UploadDetails(countingDest.count(), countingDest.countTriples(),countingDest.countQuads()) ;
+            action.log.info(format("[%d] Body: Content-Length=%d, Content-Type=%s, Charset=%s => %s : %s", 
+                                   action.id, len, ct.getContentType(), ct.getCharset(), lang.getName(),
+                                   details.detailsStr())) ;
+            return details ;
+        } catch (RiotParseException ex) {
+            action.log.info(format("[%d] Body: Content-Length=%d, Content-Type=%s, Charset=%s => %s : %s",
+                                   action.id, len, ct.getContentType(), ct.getCharset(), lang.getName(),
+                                   ex.getMessage())) ;
+            throw ex ;
         }
-    
-        ActionSPARQL.parse(action, dest, input, lang, base) ;
     }
     
     /**  Process an HTTP upload of RDF files (triples or quads)
@@ -78,9 +82,8 @@ public class Upload {
      *   is known at the start of the multipart file body
      */
     
-    public static void fileUploadWorker(HttpAction action, StreamRDF dest, boolean isGraph) {
+    public static UploadDetails fileUploadWorker(HttpAction action, StreamRDF dest) {
         String base = ActionLib.wholeRequestURL(action.request) ;
-        String item = (isGraph)?"triple":"quad" ;
         ServletFileUpload upload = new ServletFileUpload();
         long count = -1 ;
         
@@ -126,11 +129,11 @@ public class Upload {
                 StreamRDFCounting countingDest =  StreamRDFLib.count(dest) ;
                 try {
                     ActionSPARQL.parse(action, countingDest, stream, lang, base);
-                    long c = countingDest.count() ;
-                    
-                    action.log.info(format("[%d] Filename: %s, Content-Type=%s, Charset=%s => %s : %d %s%s", 
+                    UploadDetails details = new UploadDetails(countingDest.count(), countingDest.countTriples(),countingDest.countQuads()) ;
+                    action.log.info(format("[%d] Filename: %s, Content-Type=%s, Charset=%s => %s : %s", 
                                            action.id, printfilename,  ct.getContentType(), ct.getCharset(), lang.getName(),
-                                           c, item, (c==1)?"":"s")) ;
+                                           details.detailsStr())) ;
+                    return details ;
                 } catch (RiotParseException ex) {
                     action.log.info(format("[%d] Filename: %s, Content-Type=%s, Charset=%s => %s : %s",
                                            action.id, printfilename,  ct.getContentType(), ct.getCharset(), lang.getName(),
@@ -141,6 +144,7 @@ public class Upload {
         }
         catch (ActionErrorException ex) { throw ex ; }
         catch (Exception ex)            { ServletOps.errorOccurred(ex.getMessage()) ; }
+        return null ;
     }
 }
 

Added: jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/UploadDetails.java
URL: http://svn.apache.org/viewvc/jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/UploadDetails.java?rev=1602204&view=auto
==============================================================================
--- jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/UploadDetails.java (added)
+++ jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/UploadDetails.java Thu Jun 12 15:30:34 2014
@@ -0,0 +1,78 @@
+/**
+ * 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.fuseki.servlets;
+
+import org.apache.jena.atlas.json.JsonBuilder ;
+import org.apache.jena.atlas.json.JsonValue ;
+
+/** Record of an upload */
+public class UploadDetails {
+    public enum PreState { EXISTED, ABSENT, UNKNOWN } 
+    
+    private final long count ;
+    private final long tripleCount ;
+    private final long quadCount ;
+    private PreState state = PreState.UNKNOWN ;
+    
+    /*package*/ UploadDetails(long parserCount, long parserTripleCount, long parserQuadCount) {
+        this.count = parserCount ;
+        this.tripleCount = parserTripleCount ;
+        this.quadCount = parserQuadCount ;
+    }
+    
+    public String detailsStr() {
+        return String.format("Count=%d Triples=%d Quads=%d", count, tripleCount, quadCount) ;
+    }
+    
+    public static String jCount = "count" ; 
+    public static String jTriplesCount = "tripleCount" ; 
+    public static String jQuadsCount = "quadCount" ; 
+    
+    public JsonValue detailsJson() {
+        JsonBuilder b = new JsonBuilder() ;
+        b.startObject("details") ;
+        b.key(jCount).value(count) ;
+        b.key(jTriplesCount).value(tripleCount) ;
+        b.key(jQuadsCount).value(quadCount) ;
+        b.finishObject("details") ;
+        return b.build() ;
+    }
+
+    public long getCount() {
+        return count ;
+    }
+
+    public long getTripleCount() {
+        return tripleCount ;
+    }
+
+    public long getQuadCount() {
+        return quadCount ;
+    }
+
+    public void setExistedBefore(boolean existedBefore) {
+        if ( existedBefore )
+            setExistedBefore(PreState.EXISTED) ;
+        else
+            setExistedBefore(PreState.ABSENT) ;
+    }
+    public void setExistedBefore(PreState state) { this.state = state ; }
+    
+    public PreState getExistedBefore() { return state ; }
+}

Propchange: jena/Experimental/jena-fuseki2/src/main/java/org/apache/jena/fuseki/servlets/UploadDetails.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain