All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.seaborne.delta.fuseki.PatchWriteServlet Maven / Gradle / Ivy

The newest version!
/*
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  See the NOTICE file distributed with this work for additional
 *  information regarding copyright ownership.
 */

package org.seaborne.delta.fuseki;

import static java.lang.String.format;
import static org.seaborne.delta.DeltaConst.contentTypePatchBinary;
import static org.seaborne.delta.DeltaConst.ctPatchBinary;
import static org.seaborne.delta.DeltaConst.ctPatchText;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Paths;

import javax.servlet.http.HttpServlet;

import org.apache.jena.atlas.web.ContentType;
import org.apache.jena.fuseki.Fuseki;
import org.apache.jena.fuseki.server.CounterName;
import org.apache.jena.fuseki.servlets.*;
import org.apache.jena.fuseki.system.ActionCategory;
import org.apache.jena.graph.Node;
import org.apache.jena.riot.RiotException;
import org.apache.jena.riot.WebContent;
import org.apache.jena.riot.out.NodeFmtLib;
import org.apache.jena.riot.web.HttpNames;
import org.apache.jena.web.HttpSC;
import org.seaborne.patch.RDFPatch;
import org.seaborne.patch.RDFPatchOps;
import org.seaborne.patch.filelog.FilePolicy;
import org.seaborne.patch.filelog.OutputMgr;
import org.seaborne.patch.filelog.rotate.ManagedOutput;

/**
 * A patch receiver. This {@link HttpServlet servlet} writes patches to a log file
 * according to a {@link FilePolicy} and so it functions as a backup server
 * 

* It is a Fuseki servlet and not a dataset service. */ public class PatchWriteServlet extends ServletProcessor { static CounterName counterPatches = CounterName.register("RDFpatch-write", "rdf-patch.write.requests"); static CounterName counterPatchesGood = CounterName.register("RDFpatch-write", "rdf-patch.write.good"); static CounterName counterPatchesBad = CounterName.register("RDFpatch-write", "rdf-patch.write.bad"); private ManagedOutput output; public PatchWriteServlet(String dir, String fn, FilePolicy policy) { super(Fuseki.actionLog, ActionCategory.ACTION); this.output = OutputMgr.create(Paths.get(dir), fn , policy); } public PatchWriteServlet(String filename, FilePolicy policy) { super(Fuseki.actionLog, ActionCategory.ACTION); this.output = OutputMgr.create(filename, policy); } // ---- POST or OPTIONS @Override public void execPost(HttpAction action) { this.validate(action); this.operation(action); } @Override public void execOptions(HttpAction action) { ActionLib.setCommonHeadersForOptions(action); action.getResponse().setHeader(HttpNames.hAllow, "OPTIONS,POST"); action.getResponse().setHeader(HttpNames.hContentLength, "0"); } protected void validate(HttpAction action) { String method = action.getRequest().getMethod(); switch(method) { case HttpNames.METHOD_POST: break; default: ServletOps.errorMethodNotAllowed(method+" : Patch must use POST"); } String ctStr = action.getRequest().getContentType(); // Must be UTF-8 or unset. But this is wrong so often, // it is less trouble to just force UTF-8. String charset = action.getRequest().getCharacterEncoding(); if ( charset != null && ! WebContent.charsetUTF8.equals(charset) ) ServletOps.error(HttpSC.UNSUPPORTED_MEDIA_TYPE_415, "Charset must be omitted or must be UTF-8, not "+charset); // If no header Content-type - assume patch-text. ContentType contentType = ( ctStr != null ) ? ContentType.create(ctStr) : ctPatchText; if ( ! ctPatchText.equals(contentType) && ! ctPatchBinary.equals(contentType) ) ServletOps.error(HttpSC.UNSUPPORTED_MEDIA_TYPE_415, "Allowed Content-types are "+ctPatchText+" or "+ctPatchBinary+", not "+ctStr); if ( ctPatchBinary.equals(contentType) ) ServletOps.error(HttpSC.UNSUPPORTED_MEDIA_TYPE_415, contentTypePatchBinary+" not supported yet"); } protected void operation(HttpAction action) { //incCounter(action.getEndpoint(), counterPatches); try { operation$(action); //incCounter(action.getEndpoint(), counterPatchesGood) ; } catch ( ActionErrorException ex ) { //incCounter(action.getEndpoint(), counterPatchesBad) ; throw ex ; } } private void operation$(HttpAction action) { //action.log.info(format("[%d] RDF Patch Write", action.id)); try { actOnRDFPatch(action); } catch (Exception ex) { throw ex; } ServletOps.success(action); } private void actOnRDFPatch(HttpAction action) { try { String ct = action.getRequest().getContentType(); InputStream input = action.getRequestInputStream(); RDFPatch patch = RDFPatchOps.read(input); try ( OutputStream out = output.output() ) { String fn = output.currentFilename().getFileName().toString(); if ( action.verbose ) { Node id = patch.getId(); String idStr = id == null ? "" : NodeFmtLib.strNT(id); action.log.info(format("[%d] Log: %s ==>> %s", action.id, idStr, fn)); } else { action.log.info(format("[%d] Log: %s", action.id, fn)); } RDFPatchOps.write(out, patch); } ServletOps.success(action); } catch (RiotException ex) { ServletOps.errorBadRequest("RDF Patch parse error: "+ex.getMessage()); } catch (IOException ex) { ServletOps.errorBadRequest("IOException: "+ex.getMessage()); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy