org.apache.jena.fuseki.http.DatasetGraphAccessorHTTP.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.jena.fuseki.http.DatasetGraphAccessorHTTP.java

Source

/*
 * 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.http;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.*;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.SystemDefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.jena.atlas.logging.Log;
import org.apache.jena.atlas.web.TypedInputStream;
import org.apache.jena.fuseki.*;
import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFDataMgr;
import org.apache.jena.riot.WebContent;
import org.apache.jena.riot.system.IRILib;

import com.hp.hpl.jena.graph.Graph;
import com.hp.hpl.jena.graph.Node;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.sparql.graph.GraphFactory;
import com.hp.hpl.jena.sparql.graph.UnmodifiableGraph;

public class DatasetGraphAccessorHTTP implements DatasetGraphAccessor {
    private final String remote;

    /** Create a DatasetUpdater for the remote URL */
    public DatasetGraphAccessorHTTP(String remote) {
        this.remote = remote;
    }

    @Override
    public Graph httpGet() {
        return doGet(targetDefault());
    }

    @Override
    public Graph httpGet(Node graphName) {
        return doGet(target(graphName));
    }

    private Graph doGet(String url) {
        HttpUriRequest httpGet = new HttpGet(url);
        try {
            return exec(url, null, httpGet, true);
        } catch (FusekiNotFoundException ex) {
            return null;
        }
    }

    @Override
    public boolean httpHead() {
        return doHead(targetDefault());
    }

    @Override
    public boolean httpHead(Node graphName) {
        return doHead(target(graphName));
    }

    private boolean doHead(String url) {
        HttpUriRequest httpHead = new HttpHead(url);
        try {
            exec(url, null, httpHead, false);
            return true;
        } catch (FusekiRequestException ex) {
            if (ex.getStatusCode() == HttpSC.NOT_FOUND_404)
                return false;
            throw ex;
        }
    }

    @Override
    public void httpPut(Graph data) {
        doPut(targetDefault(), data);
    }

    @Override
    public void httpPut(Node graphName, Graph data) {
        doPut(target(graphName), data);
    }

    private void doPut(String url, Graph data) {
        HttpUriRequest httpPut = new HttpPut(url);
        exec(url, data, httpPut, false);
    }

    @Override
    public void httpDelete() {
        doDelete(targetDefault());
    }

    @Override
    public void httpDelete(Node graphName) {
        doDelete(target(graphName));
    }

    private boolean doDelete(String url) {
        try {
            HttpUriRequest httpDelete = new HttpDelete(url);
            exec(url, null, httpDelete, false);
            return true;
        } catch (FusekiNotFoundException ex) {
            return false;
        }
    }

    @Override
    public void httpPost(Graph data) {
        doPost(targetDefault(), data);
    }

    @Override
    public void httpPost(Node graphName, Graph data) {
        doPost(target(graphName), data);
    }

    private void doPost(String url, Graph data) {
        HttpUriRequest httpPost = new HttpPost(url);
        exec(url, data, httpPost, false);
    }

    @Override
    public void httpPatch(Graph data) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void httpPatch(Node graphName, Graph data) {
        throw new UnsupportedOperationException();
    }

    private String targetDefault() {
        return remote + "?" + HttpNames.paramGraphDefault + "=";
    }

    private String target(Node name) {
        if (!name.isURI())
            throw new FusekiException("Not a URI: " + name);
        String guri = name.getURI();
        // Encode
        guri = IRILib.encodeUriComponent(guri);
        return remote + "?" + HttpNames.paramGraph + "=" + guri;
    }

    static private HttpParams httpParams = createHttpParams();

    static private HttpParams createHttpParams() {
        HttpParams httpParams$ = new BasicHttpParams();
        // See DefaultHttpClient.createHttpParams
        HttpProtocolParams.setVersion(httpParams$, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(httpParams$, WebContent.charsetUTF8);
        HttpProtocolParams.setUseExpectContinue(httpParams$, true);
        HttpConnectionParams.setTcpNoDelay(httpParams$, true);
        HttpConnectionParams.setSocketBufferSize(httpParams$, 32 * 1024);
        HttpProtocolParams.setUserAgent(httpParams$, Fuseki.NAME + "/" + Fuseki.VERSION);
        return httpParams$;
    }

    private static String getHeader(HttpResponse response, String headerName) {
        Header h = response.getLastHeader(headerName);
        if (h == null)
            return null;
        return h.getValue();
    }

    private Graph exec(String targetStr, Graph graphToSend, HttpUriRequest httpRequest, boolean processBody) {
        HttpClient httpclient = new SystemDefaultHttpClient(httpParams);

        if (graphToSend != null) {
            // ??? httpRequest isa Post
            // Impedence mismatch - is there a better way?
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            Model model = ModelFactory.createModelForGraph(graphToSend);
            model.write(out, "RDF/XML");
            byte[] bytes = out.toByteArray();
            ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
            InputStreamEntity reqEntity = new InputStreamEntity(in, bytes.length);
            reqEntity.setContentType(WebContent.contentTypeRDFXML);
            reqEntity.setContentEncoding(WebContent.charsetUTF8);
            HttpEntity entity = reqEntity;
            ((HttpEntityEnclosingRequestBase) httpRequest).setEntity(entity);
        }
        TypedInputStream ts = null;
        // httpclient.getParams().setXXX
        try {
            HttpResponse response = httpclient.execute(httpRequest);

            int responseCode = response.getStatusLine().getStatusCode();
            String responseMessage = response.getStatusLine().getReasonPhrase();

            if (HttpSC.isRedirection(responseCode))
                // Not implemented yet.
                throw FusekiRequestException.create(responseCode, responseMessage);

            // Other 400 and 500 - errors

            if (HttpSC.isClientError(responseCode) || HttpSC.isServerError(responseCode))
                throw FusekiRequestException.create(responseCode, responseMessage);

            if (responseCode == HttpSC.NO_CONTENT_204)
                return null;
            if (responseCode == HttpSC.CREATED_201)
                return null;

            if (responseCode != HttpSC.OK_200) {
                Log.warn(this, "Unexpected status code");
                throw FusekiRequestException.create(responseCode, responseMessage);
            }

            // May not have a body.
            String ct = getHeader(response, HttpNames.hContentType);
            if (ct == null) {
                HttpEntity entity = response.getEntity();

                if (entity != null) {
                    InputStream instream = entity.getContent();
                    // Read to completion?
                    instream.close();
                }
                return null;
            }

            // Tidy. See ConNeg / MediaType.
            String x = getHeader(response, HttpNames.hContentType);
            String y[] = x.split(";");
            String contentType = null;
            if (y[0] != null)
                contentType = y[0].trim();
            String charset = null;
            if (y.length > 1 && y[1] != null)
                charset = y[1].trim();

            // Get hold of the response entity
            HttpEntity entity = response.getEntity();

            if (entity != null) {
                InputStream instream = entity.getContent();
                //                String mimeType = ConNeg.chooseContentType(request, rdfOffer, ConNeg.acceptRDFXML).getAcceptType() ;
                //                String charset = ConNeg.chooseCharset(request, charsetOffer, ConNeg.charsetUTF8).getAcceptType() ;
                ts = new TypedInputStream(instream, contentType, charset, null);
            }
            Graph graph = GraphFactory.createGraphMem();
            if (processBody)
                readGraph(graph, ts, null);
            if (ts != null)
                ts.close();
            Graph graph2 = new UnmodifiableGraph(graph);
            return graph2;
        } catch (IOException ex) {
            httpRequest.abort();
            return null;
        }
    }

    private void readGraph(Graph graph, TypedInputStream ts, String base) {
        // Yes - we ignore the charset.
        // Either it's XML and so the XML parser deals with it, or the 
        // language determines the charset and the parsers offer InputStreams.   

        Lang lang = WebContent.contentTypeToLang(ts.getContentType());
        if (lang == null)
            throw new FusekiException("Unknown lang for " + ts.getMediaType());
        RDFDataMgr.read(graph, base, lang);
    }
}