/** * 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 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 ; import java.io.InputStream ; import java.util.zip.GZIPInputStream ; import org.apache.commons.fileupload.FileItemIterator ; import org.apache.commons.fileupload.FileItemStream ; import org.apache.commons.fileupload.servlet.ServletFileUpload ; import org.apache.commons.fileupload.util.Streams ; import org.apache.jena.atlas.io.IO ; import org.apache.jena.atlas.web.ContentType ; 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 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 UploadDetails incomingData(HttpAction action, StreamRDF dest) { ContentType ct = FusekiLib.getContentType(action) ; if ( ct == null ) { ServletOps.errorBadRequest("No content type") ; return null ; } if ( matchContentType(ctMultipartFormData, ct) ) { return fileUploadWorker(action, dest) ; } // Single graph (or quads) in body. String base = ActionLib.wholeRequestURL(action.request) ; Lang lang = RDFLanguages.contentTypeToLang(ct.getContentType()) ; if ( lang == null ) { ServletOps.errorBadRequest("Unknown content type for triples: " + ct) ; return null ; } InputStream input = null ; try { input = action.request.getInputStream() ; } catch (IOException ex) { IO.exception(ex) ; } int len = action.request.getContentLength() ; 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 ; } } /** Process an HTTP upload of RDF files (triples or quads) * Stream straight into a graph or dataset -- unlike SPARQL_Upload the destination * is known at the start of the multipart file body */ public static UploadDetails fileUploadWorker(HttpAction action, StreamRDF dest) { String base = ActionLib.wholeRequestURL(action.request) ; ServletFileUpload upload = new ServletFileUpload(); //log.info(format("[%d] Upload: Field=%s ignored", action.id, fieldName)) ; // Overall counting. StreamRDFCounting countingDest = StreamRDFLib.count(dest) ; try { FileItemIterator iter = upload.getItemIterator(action.request); while (iter.hasNext()) { FileItemStream fileStream = iter.next(); if (fileStream.isFormField()) { // Ignore? String fieldName = fileStream.getFieldName() ; InputStream stream = fileStream.openStream(); String value = Streams.asString(stream, "UTF-8") ; ServletOps.errorBadRequest(format("Only files accepted in multipart file upload (got %s=%s)",fieldName, value)) ; } //Ignore the field name. //String fieldName = fileStream.getFieldName(); InputStream stream = fileStream.openStream(); // Process the input stream String contentTypeHeader = fileStream.getContentType() ; ContentType ct = ContentType.create(contentTypeHeader) ; Lang lang = null ; if ( ! matchContentType(ctTextPlain, ct) ) lang = RDFLanguages.contentTypeToLang(ct.getContentType()) ; if ( lang == null ) { String name = fileStream.getName() ; if ( name == null || name.equals("") ) ServletOps.errorBadRequest("No name for content - can't determine RDF syntax") ; lang = RDFLanguages.filenameToLang(name) ; if (name.endsWith(".gz")) stream = new GZIPInputStream(stream); } if ( lang == null ) // Desperate. lang = RDFLanguages.RDFXML ; String printfilename = fileStream.getName() ; if ( printfilename == null || printfilename.equals("") ) printfilename = "<none>" ; // Before // action.log.info(format("[%d] Filename: %s, Content-Type=%s, Charset=%s => %s", // action.id, printfilename, ct.getContentType(), ct.getCharset(), lang.getName())) ; // count just this step StreamRDFCounting countingDest2 = StreamRDFLib.count(countingDest) ; try { ActionSPARQL.parse(action, countingDest2, stream, lang, base); UploadDetails details1 = new UploadDetails(countingDest2.count(), countingDest2.countTriples(),countingDest2.countQuads()) ; action.log.info(format("[%d] Filename: %s, Content-Type=%s, Charset=%s => %s : %s", action.id, printfilename, ct.getContentType(), ct.getCharset(), lang.getName(), details1.detailsStr())) ; } 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(), ex.getMessage())) ; throw ex ; } } } catch (ActionErrorException ex) { throw ex ; } catch (Exception ex) { ServletOps.errorOccurred(ex.getMessage()) ; } // Overall results. UploadDetails details = new UploadDetails(countingDest.count(), countingDest.countTriples(),countingDest.countQuads()) ; return details ; } }