eu.fusepool.p3.transformer.client.TransformerClientImpl.java Source code

Java tutorial

Introduction

Here is the source code for eu.fusepool.p3.transformer.client.TransformerClientImpl.java

Source

/*
 * Copyright (C) 2014 Bern University of Applied Sciences.
 *
 * 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.
 */
package eu.fusepool.p3.transformer.client;

import eu.fusepool.p3.transformer.commons.Entity;
import eu.fusepool.p3.transformer.commons.util.InputStreamEntity;
import eu.fusepool.p3.vocab.TRANSFORMER;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import javax.activation.MimeType;
import javax.activation.MimeTypeParseException;
import org.apache.clerezza.rdf.core.Graph;
import org.apache.clerezza.rdf.core.Literal;
import org.apache.clerezza.rdf.core.UriRef;
import org.apache.clerezza.rdf.core.serializedform.Parser;
import org.apache.clerezza.rdf.utils.GraphNode;
import org.apache.commons.io.IOUtils;

/**
 * An implementation of {@link Transformer} to access a Transformer identified 
 * by a URI
 * @author Gabor, reto
 */
public class TransformerClientImpl implements Transformer {

    final private URI uri;
    final private Set<MimeType> supportedInputFormats;
    final private Set<MimeType> supportedOutputFormats;

    public TransformerClientImpl(URI _uri) {
        uri = _uri;
        supportedInputFormats = new HashSet<>();
        supportedOutputFormats = new HashSet<>();
        setMimeTypes();
    }

    public TransformerClientImpl(String uriString) {
        try {
            uri = new URI(uriString);
            supportedInputFormats = new HashSet<>();
            supportedOutputFormats = new HashSet<>();
            setMimeTypes();
        } catch (URISyntaxException e) {
            throw new RuntimeException("URI syntax error!", e);
        }
    }

    private void setMimeTypes() {
        HttpURLConnection connection = null;
        try {
            connection = (HttpURLConnection) uri.toURL().openConnection();
            connection.setRequestMethod("GET");
            connection.setRequestProperty("Accept", "text/turtle");

            final Parser parser = Parser.getInstance();
            final UriRef transformerRes = new UriRef(uri.toString());
            final Graph graph = parser.parse(connection.getInputStream(), "text/turtle", transformerRes);
            final GraphNode transformerNode = new GraphNode(transformerRes, graph);
            {
                final Iterator<Literal> sifIter = transformerNode.getLiterals(TRANSFORMER.supportedInputFormat);
                while (sifIter.hasNext()) {
                    Literal lit = sifIter.next();
                    try {
                        supportedInputFormats.add(new MimeType(lit.getLexicalForm()));
                    } catch (MimeTypeParseException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
            {
                final Iterator<Literal> sofIter = transformerNode.getLiterals(TRANSFORMER.supportedOutputFormat);
                while (sofIter.hasNext()) {
                    Literal lit = sofIter.next();
                    try {
                        supportedOutputFormats.add(new MimeType(lit.getLexicalForm()));
                    } catch (MimeTypeParseException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        } catch (IOException e) {
            throw new RuntimeException("Cannot establish connection to " + uri.toString() + " !", e);
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    @Override
    public Entity transform(Entity entity, MimeType... acceptedFormats) {
        HttpURLConnection connection = null;
        try {
            final URL transfromerUrl = uri.toURL();
            connection = (HttpURLConnection) transfromerUrl.openConnection();
            connection.setRequestMethod("POST");
            String acceptHeaderValue = null;
            if (acceptedFormats.length > 0) {
                final StringWriter acceptString = new StringWriter();
                double q = 1;
                for (MimeType mimeType : acceptedFormats) {
                    acceptString.write(mimeType.toString());
                    acceptString.write("; q=");
                    acceptString.write(Double.toString(q));
                    q = q * 0.9;
                    acceptString.write(", ");
                }
                acceptHeaderValue = acceptString.toString();
                connection.setRequestProperty("Accept", acceptHeaderValue);
            }

            connection.setRequestProperty("Content-Type", entity.getType().toString());
            if (entity.getContentLocation() != null) {
                connection.setRequestProperty("Content-Location", entity.getContentLocation().toString());
            }

            connection.setDoOutput(true);
            connection.setUseCaches(false);
            try (OutputStream out = connection.getOutputStream()) {
                entity.writeData(out);
            }
            final int responseCode = connection.getResponseCode();
            if (responseCode == 200) {
                return getResponseEntity(connection);
            }
            if ((responseCode == 202) || (responseCode == 201)) {
                final String location = connection.getHeaderField("Location");
                if (location == null) {
                    throw new RuntimeException("No location header in first 202 response");
                }
                return getAsyncResponseEntity(new URL(transfromerUrl, location), acceptHeaderValue);
            }
            throw new UnexpectedResponseException(responseCode, getResponseEntity(connection));

        } catch (IOException e) {
            throw new RuntimeException("Cannot establish connection to " + uri.toString() + " !", e);
        } catch (MimeTypeParseException ex) {
            throw new RuntimeException("Error parsing MediaType returned from Server. ", ex);
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    @Override
    public boolean accepts(MimeType type) {
        for (MimeType m : supportedInputFormats) {
            if ((m.match(type)) || m.getPrimaryType().equals("*")
                    || (m.getSubType().equals("*") && m.getPrimaryType().equals(type.getPrimaryType()))) {
                return true;
            }
        }
        return false;
    }

    @Override
    public Set<MimeType> getSupportedInputFormats() {
        return supportedInputFormats;
    }

    @Override
    public Set<MimeType> getSupportedOutputFormats() {
        return supportedOutputFormats;
    }

    private Entity getResponseEntity(HttpURLConnection connection) throws IOException, MimeTypeParseException {
        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
        if (connection.getResponseCode() < 400) {
            IOUtils.copy(connection.getInputStream(), baos);
        } else {
            IOUtils.copy(connection.getErrorStream(), baos);
        }

        final byte[] bytes = baos.toByteArray();

        final String resultContentTypeString = connection.getHeaderField("Content-Type");
        final MimeType resultType = resultContentTypeString != null ? new MimeType(resultContentTypeString)
                : new MimeType("application", "octet-stream");
        return new InputStreamEntity() {

            @Override
            public MimeType getType() {
                return resultType;
            }

            @Override
            public InputStream getData() throws IOException {
                return new ByteArrayInputStream(bytes);
            }
        };
    }

    private Entity getAsyncResponseEntity(URL url, String acceptHeaderValue) {
        //recursive function would be nicer, but this saves memory
        int counter = 0;
        while (true) {
            HttpURLConnection connection = null;
            try {
                connection = (HttpURLConnection) url.openConnection();
                if (acceptHeaderValue != null) {
                    connection.setRequestProperty("Accept", acceptHeaderValue);
                }

                final int responseCode = connection.getResponseCode();
                if (responseCode == 200) {
                    return getResponseEntity(connection);
                }
                if (responseCode != 202) {
                    throw new RuntimeException("Unexpected response code: " + responseCode);
                }
            } catch (IOException e) {
                throw new RuntimeException("Cannot establish connection to " + uri.toString() + " !", e);
            } catch (MimeTypeParseException ex) {
                throw new RuntimeException("Error parsing MediaType returned from Server. ", ex);
            } finally {
                if (connection != null) {
                    connection.disconnect();
                }
            }
            //Check every half second for the first 5 seconds, Evrey 10 second for the following 10 minutes, every two minutes afterwards
            final int interval = counter < 10 ? 500 : counter < 70 ? 10000 : 120000;
            counter++;
            try {
                Thread.sleep(interval);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

}