com.github.podd.resources.RestletPoddClientImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.github.podd.resources.RestletPoddClientImpl.java

Source

/**
 * PODD is an OWL ontology database used for scientific project management
 *
 * Copyright (C) 2009-2013 The University Of Queensland
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the
 * GNU Affero General Public License as published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 */
package com.github.podd.resources;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.SocketTimeoutException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.commons.io.IOUtils;
//import org.apache.commons.io.IOUtils;
import org.openrdf.model.Literal;
import org.openrdf.model.Model;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.model.ValueFactory;
import org.openrdf.model.impl.LinkedHashModel;
import org.openrdf.model.vocabulary.RDFS;
import org.openrdf.queryrender.RenderUtils;
import org.openrdf.rio.RDFFormat;
import org.openrdf.rio.RDFHandlerException;
import org.openrdf.rio.RDFParseException;
import org.openrdf.rio.Rio;
import org.openrdf.rio.UnsupportedRDFormatException;
import org.restlet.Context;
import org.restlet.data.CharacterSet;
import org.restlet.data.CookieSetting;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Status;
import org.restlet.representation.InputRepresentation;
import org.restlet.representation.ReaderRepresentation;
import org.restlet.representation.Representation;
import org.restlet.resource.ClientResource;
import org.restlet.resource.ResourceException;
import org.restlet.util.Series;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.github.ansell.propertyutil.PropertyUtil;
import com.github.ansell.restletutils.RestletUtilMediaType;
import com.github.ansell.restletutils.RestletUtilRole;
import com.github.ansell.restletutils.SesameRealmConstants;
import com.github.podd.api.DanglingObjectPolicy;
import com.github.podd.api.DataReferenceVerificationPolicy;
import com.github.podd.api.data.DataReference;
import com.github.podd.api.data.DataReferenceConstants;
import com.github.podd.exception.PoddException;
import com.github.podd.ontologies.PODDBASE;
import com.github.podd.ontologies.PODDSCIENCE;
import com.github.podd.utils.InferredOWLOntologyID;
import com.github.podd.utils.OntologyUtils;
import com.github.podd.utils.PODD;
import com.github.podd.utils.PoddRoles;
import com.github.podd.utils.PoddUser;
import com.github.podd.utils.PoddWebConstants;

/**
 * Restlet based PODD Client implementation.
 *
 * @author Peter Ansell p_ansell@yahoo.com
 */
public class RestletPoddClientImpl implements PoddClient, Runnable {
    protected final Logger log = LoggerFactory.getLogger(this.getClass());

    public final static String DEFAULT_PROPERTY_BUNDLE = "poddclient";

    public static final String PROP_PODD_SERVER_URL = "podd.serverurl";

    public static final String DEFAULT_PODD_SERVER_URL = null;// "http://localhost:8080/podd/";

    public static final String PROP_PODD_USERNAME = "podd.username";

    public static final String PROP_PODD_PASSWORD = "podd.password";

    public final static String TEMP_UUID_PREFIX = "urn:temp:uuid:";
    public final static String PATH_SPARQL2 = "sparql2";
    private Series<CookieSetting> currentCookies = new Series<CookieSetting>(CookieSetting.class);

    private PropertyUtil props;

    private volatile String serverUrl = null;

    /**
     * Shortcut to {@link PODD#VF}
     */
    protected final static ValueFactory vf = PODD.VF;

    public RestletPoddClientImpl() {
        this.props = new PropertyUtil(RestletPoddClientImpl.DEFAULT_PROPERTY_BUNDLE);
    }

    public RestletPoddClientImpl(final String poddServerUrl) {
        this();
        String url = this.getProps().get(RestletPoddClientImpl.PROP_PODD_SERVER_URL, null);

        if (url == null) {
            this.serverUrl = poddServerUrl;
        } else {
            this.serverUrl = url;
        }
    }

    @Override
    public void addRole(final String userIdentifier, final RestletUtilRole role,
            final InferredOWLOntologyID artifact) throws PoddException {
        this.log.debug("cookies: {}", this.currentCookies);

        final ClientResource resource = new ClientResource(this.getUrl(PoddWebConstants.PATH_USER_ROLES));
        resource.getCookies().addAll(this.currentCookies);
        resource.addQueryParameter(PoddWebConstants.KEY_USER_IDENTIFIER, userIdentifier);

        final Map<RestletUtilRole, Collection<URI>> mappings = new HashMap<>();
        final Collection<URI> artifacts = Arrays.asList(artifact.getOntologyIRI().toOpenRDFURI());
        mappings.put(role, artifacts);

        final Model model = new LinkedHashModel();
        PoddRoles.dumpRoleMappingsUser(mappings, model);

        final Representation post = this.postRdf(resource, model);

        try {
            final Model parsedStatements = this.parseRdf(post);

            if (!parsedStatements.contains(null, SesameRealmConstants.OAS_USERIDENTIFIER,
                    PODD.VF.createLiteral(userIdentifier))) {
                this.log.warn("Role edit response did not seem to contain the user identifier");
            }
        } catch (final IOException e) {
            try {
                throw new IOException("Could not parse results due to an IOException", e);
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }
    }

    @Override
    public InferredOWLOntologyID appendArtifact(final InferredOWLOntologyID ontologyIRI,
            final InputStream partialInputStream, final RDFFormat format) throws PoddException {
        return this.appendArtifact(ontologyIRI, partialInputStream, format, DanglingObjectPolicy.REPORT,
                DataReferenceVerificationPolicy.DO_NOT_VERIFY);
    }

    @Override
    public InferredOWLOntologyID appendArtifact(final InferredOWLOntologyID artifactID,
            final InputStream partialInputStream, final RDFFormat format,
            final DanglingObjectPolicy danglingObjectPolicy,
            final DataReferenceVerificationPolicy dataReferenceVerificationPolicy) throws PoddException {
        final InputRepresentation rep = new InputRepresentation(partialInputStream,
                MediaType.valueOf(format.getDefaultMIMEType()));

        final ClientResource resource = new ClientResource(this.getUrl(PoddWebConstants.PATH_ARTIFACT_EDIT));
        resource.getCookies().addAll(this.currentCookies);

        this.log.debug("cookies: {}", this.currentCookies);

        resource.addQueryParameter(PoddWebConstants.KEY_EDIT_WITH_REPLACE, Boolean.toString(false));
        resource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_IDENTIFIER,
                artifactID.getOntologyIRI().toString());
        resource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_VERSION_IDENTIFIER,
                artifactID.getVersionIRI().toString());
        if (danglingObjectPolicy == DanglingObjectPolicy.FORCE_CLEAN) {
            resource.addQueryParameter(PoddWebConstants.KEY_EDIT_WITH_FORCE, "true");
        }
        if (dataReferenceVerificationPolicy == DataReferenceVerificationPolicy.VERIFY) {
            resource.addQueryParameter(PoddWebConstants.KEY_EDIT_VERIFY_FILE_REFERENCES, "true");
        }
        resource.addQueryParameter("format", format.getDefaultMIMEType());

        // Request the results in Turtle to reduce the bandwidth
        final Representation post = resource.post(rep, MediaType.APPLICATION_RDF_TURTLE);

        try {
            final Model parsedStatements = this.parseRdf(post);

            final Collection<InferredOWLOntologyID> result = OntologyUtils.modelToOntologyIDs(parsedStatements,
                    true, false);

            if (!result.isEmpty()) {
                return result.iterator().next();
            }

            throw new Exception("Failed to verify that the artifact was uploaded correctly.");
        } catch (final Exception e) {
            System.out.println(e.toString());
        }
        return null;
    }

    @Override
    public Map<InferredOWLOntologyID, InferredOWLOntologyID> appendArtifacts(
            final Map<InferredOWLOntologyID, Model> uploadQueue) throws PoddException {
        final ConcurrentMap<InferredOWLOntologyID, InferredOWLOntologyID> resultMap = new ConcurrentHashMap<>();
        for (final Entry<InferredOWLOntologyID, Model> nextUpload : uploadQueue.entrySet()) {
            try {
                final StringWriter writer = new StringWriter(4096);
                Rio.write(nextUpload.getValue(), writer, RDFFormat.RDFJSON);
                final InferredOWLOntologyID newID = this.appendArtifact(nextUpload.getKey(),
                        new ByteArrayInputStream(writer.toString().getBytes(Charset.forName("UTF-8"))),
                        RDFFormat.RDFJSON);

                if (newID == null) {
                    this.log.error("Did not find a valid result from append artifact: {}", nextUpload.getKey());
                } else if (nextUpload.getKey().equals(newID)) {
                    this.log.error("Result from append artifact was not changed, as expected. {} {}",
                            nextUpload.getKey(), newID);
                } else {
                    resultMap.putIfAbsent(nextUpload.getKey(), newID);
                }
            } catch (final RDFHandlerException e) {
                this.log.error("Found exception generating upload body: ", e);
            }
        }
        return resultMap;
    }

    @Override
    public boolean autologin() throws PoddException {
        final String username = this.getProps().get(RestletPoddClientImpl.PROP_PODD_USERNAME, null);
        final String password = this.getProps().get(RestletPoddClientImpl.PROP_PODD_PASSWORD, null);

        Objects.requireNonNull(username,
                "Cannot automatically login as username was not defined in poddclient.properties");
        Objects.requireNonNull(password,
                "Cannot automatically login as password was not defined in poddclient.properties");

        return this.login(username, password);
    }

    @Override
    public PoddUser createUser(final PoddUser user) throws PoddException {
        try {
            final Model model = new LinkedHashModel();
            user.toModel(model, true);
            final ByteArrayOutputStream output = new ByteArrayOutputStream(4096);
            Rio.write(model, output, RDFFormat.RDFJSON);
            final InputRepresentation rep = new InputRepresentation(new ByteArrayInputStream(output.toByteArray()),
                    MediaType.valueOf(RDFFormat.RDFJSON.getDefaultMIMEType()));

            final ClientResource resource = new ClientResource(this.getUrl(PoddWebConstants.PATH_USER_ADD));
            resource.getCookies().addAll(this.currentCookies);

            this.log.debug("cookies: {}", this.currentCookies);

            resource.addQueryParameter("format", RDFFormat.RDFJSON.getDefaultMIMEType());

            // Request the results in Turtle to reduce the bandwidth
            final Representation post = resource.post(rep, MediaType.APPLICATION_RDF_TURTLE);

            final Model parsedStatements = this.parseRdf(post);

            final PoddUser result = PoddUser.fromModel(model);

            return result;
        } catch (final IOException | RDFHandlerException | ResourceException e) {
            System.out.println(e.toString());
        }
        return null;
    }

    @Override
    public boolean deleteArtifact(final InferredOWLOntologyID artifactId) throws PoddException {
        this.log.debug("cookies: {}", this.currentCookies);

        final ClientResource resource = new ClientResource(this.getUrl(PoddWebConstants.PATH_ARTIFACT_DELETE));
        resource.getCookies().addAll(this.currentCookies);

        resource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_IDENTIFIER,
                artifactId.getOntologyIRI().toString());

        if (artifactId.getVersionIRI() != null) {
            // FIXME: Versions are not supported in general by PODD, but they are important for
            // verifying the state of the client to allow for early failure in cases where the
            // client is out of date.
            resource.addQueryParameter("versionUri", artifactId.getVersionIRI().toString());
        }

        resource.delete();

        if (resource.getStatus().isSuccess()) {
            return true;
        } else {
            try {
                throw new Exception(
                        "Failed to successfully delete artifact: " + artifactId.getOntologyIRI().toString());
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return false;
    }

    public Representation doSPARQL2(final String queryString, final Collection<InferredOWLOntologyID> artifactIds)
            throws PoddException {
        this.log.debug("cookies: {}", this.currentCookies);

        final ClientResource resource = new ClientResource(this.getUrl(PoddWebConstants.PATH_SPARQL));
        resource.getCookies().addAll(this.currentCookies);

        final Form form = new Form();
        form.add(PoddWebConstants.KEY_SPARQLQUERY, queryString);

        // TODO: Parse query to make sure it is syntactically valid before sending query
        resource.addQueryParameter(PoddWebConstants.KEY_SPARQLQUERY, queryString);

        try {
            final Representation get = resource.get(MediaType.APPLICATION_ALL_XML);
            /*
            try {
            String d = get.getText().replaceAll("(.*)version=(.*)", "");
            String f = d.replaceAll("(.*)sparql(.*)", "").replaceAll("(.*)result(.*)", "");
            System.out.println(f);
            } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            }
            */

            try {
                DocumentBuilder dBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();

                InputStream in = IOUtils.toInputStream(get.getText());
                Document doc = dBuilder.parse(in);
                System.out.println("\r\n" + "============================== \r\n" + " PODD Query Results \r\n"
                        + "==============================");

                if (doc.hasChildNodes()) {
                    printNote(doc.getChildNodes());
                }

            } catch (Exception e) {
                System.out.println(e.getMessage());
            }

            return get;

        } catch (final ResourceException e) {
            if (e.getStatus().equals(Status.CLIENT_ERROR_PRECONDITION_FAILED)) {
                System.out.println("");
                System.out.println("Error: Access denied in server " + this.serverUrl
                        + " with the login credentials provided in ~/poddclient.properties.");
                // Precondition failed indicates that they do not have access to any artifacts, so
                // return empty results set
                return null;
            }

            System.out.println(e.toString());
        } catch (final UnsupportedRDFormatException e) {
            // Attempt to retry the request once to avoid random restlet failures stopping the
            // entire process
            try {
                final Representation get = resource.post(form.getWebRepresentation(CharacterSet.UTF_8),
                        RestletUtilMediaType.APPLICATION_RDF_JSON);

                // Pass the desired format to the get method of the ClientResource
                // final Representation get =
                // resource.get(RestletUtilMediaType.APPLICATION_RDF_JSON);

                final StringWriter writer = new StringWriter(4096);

                get.write(writer);
                return null;
            } catch (final ResourceException e1) {
                if (e1.getStatus().equals(Status.CLIENT_ERROR_PRECONDITION_FAILED)) {
                    System.out.println("");
                    System.out.println("Error: Access denied in server " + this.serverUrl
                            + " with login credentials provided in ~/poddclient.properties.");
                    // Precondition failed indicates that they do not have access to any artifacts,
                    // so
                    // return empty results set
                    return null;
                } else {
                    System.out.println(e.toString());
                }
            } catch (final IOException | UnsupportedRDFormatException e1) {
                System.out.println(e.toString());
            }
        }
        return null;
    }

    public Representation doSPARQL3(final String queryString, final Collection<InferredOWLOntologyID> artifactIds)
            throws PoddException {
        this.log.debug("cookies: {}", this.currentCookies);
        //final Context context = new Context();
        //context.getParameters().add("socketTimeout", "10000");
        //context.getParameters().add("connectionTimeout", "10000"); 
        final ClientResource resource = new ClientResource(this.getUrl(PATH_SPARQL2));

        resource.getCookies().addAll(this.currentCookies);

        final Form form = new Form();
        form.add(PoddWebConstants.KEY_SPARQLQUERY, queryString);

        // TODO: Parse query to make sure it is syntactically valid before sending query
        resource.addQueryParameter(PoddWebConstants.KEY_SPARQLQUERY, queryString);

        try {
            final Representation get = resource.get(MediaType.APPLICATION_ALL_XML);
            /*
            try {
             String d = get.getText().replaceAll("(.*)version=(.*)", "");
             String f = d.replaceAll("(.*)sparql(.*)", "").replaceAll("(.*)result(.*)", "");
             System.out.println(f);
            } catch (IOException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
            }
            */

            try {
                DocumentBuilder dBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
                String d = get.getText().replaceAll("(.*)version=(.*)", "");
                String f = d.replaceAll("(.*)sparql(.*)", "");
                InputStream in = IOUtils
                        .toInputStream("<?xml version='1.0' encoding='UTF-8'?>" + " <r>" + f + " </r>", "UTF-8");
                Document doc = dBuilder.parse(in);
                System.out.println("\r\n" + "============================== \r\n" + " PODD Query Results \r\n"
                        + "==============================");

                if (doc.hasChildNodes()) {
                    printNote3(doc.getChildNodes());
                }

            } catch (Exception e) {
                System.out.println(e.getMessage());
            }

            return get;

        } catch (final ResourceException e) {
            if (e.getStatus().equals(Status.CLIENT_ERROR_PRECONDITION_FAILED)) {
                System.out.println("");
                System.out.println("Error: Access denied in server " + this.serverUrl
                        + " with the login credentials provided in ~/poddclient.properties.");
                // Precondition failed indicates that they do not have access to any artifacts, so
                // return empty results set
                return null;
            }

            System.out.println(e.toString());
        } catch (final UnsupportedRDFormatException e) {
            // Attempt to retry the request once to avoid random restlet failures stopping the
            // entire process
            try {
                final Representation get = resource.post(form.getWebRepresentation(CharacterSet.UTF_8),
                        RestletUtilMediaType.APPLICATION_RDF_JSON);

                // Pass the desired format to the get method of the ClientResource
                // final Representation get =
                // resource.get(RestletUtilMediaType.APPLICATION_RDF_JSON);

                final StringWriter writer = new StringWriter(4096);

                get.write(writer);
                return null;
            } catch (final ResourceException e1) {
                if (e1.getStatus().equals(Status.CLIENT_ERROR_PRECONDITION_FAILED)) {
                    System.out.println("");
                    System.out.println("Error: Access denied in server " + this.serverUrl
                            + " with login credentials provided in ~/poddclient.properties.");
                    // Precondition failed indicates that they do not have access to any artifacts,
                    // so
                    // return empty results set
                    return null;
                } else {
                    System.out.println("Error: Unable to find the requested data in PODD");
                    System.out.println(e.toString());
                }
            } catch (final IOException | UnsupportedRDFormatException e1) {
                System.out.println("Error: Unable to find the requested data in PODD");
                System.out.println(e.toString());
                return null;
            }

        }

        // Your database code here

        return null;
    }

    private static void printNote(NodeList nodeList) {

        for (int count = 0; count < nodeList.getLength(); count++) {

            Node tempNode = nodeList.item(count);

            // make sure it's element node.
            if (tempNode.getNodeType() == Node.ELEMENT_NODE) {

                // get node name and value
                if (!tempNode.getNodeName().startsWith("rdf:") && tempNode.getTextContent().length() > 0) {
                    if (tempNode.getNodeName().startsWith("rdfs:label")) {

                        System.out.println("Name" + ": " + tempNode.getTextContent());
                    } else if (tempNode.getNodeName().startsWith("rdfs:comment")) {
                        System.out.println("Description" + ": " + tempNode.getTextContent());
                    } else if (tempNode.getNodeName().startsWith("hasPotColumnNumberOverall")) {
                        System.out.println("Lane" + ": " + tempNode.getTextContent());
                    } else if (tempNode.getNodeName().startsWith("hasPotPositionTray")) {
                        System.out.println("Position" + ": " + tempNode.getTextContent());
                    } else {
                        System.out.println(tempNode.getNodeName() + ": " + tempNode.getTextContent());
                    }

                }

                if (tempNode.hasChildNodes()) {
                    // loop again if has child node

                    printNote(tempNode.getChildNodes());
                    System.out.println("");

                }

            }

        }
    }

    private static void printNote3(NodeList nodeList) {

        for (int count = 0; count < nodeList.getLength(); count++) {

            Node tempNode = nodeList.item(count);

            // make sure it's element node.
            if (tempNode.getNodeType() == Node.ELEMENT_NODE) {

                // get node name and value

                if (tempNode.getNodeName().startsWith("binding")) {

                    if (tempNode.getAttributes().getNamedItem("name").getTextContent().equals("Experiment")) {

                        System.out.println("");
                        System.out.print(tempNode.getAttributes().getNamedItem("name").getTextContent() + " :  \t");
                    } else {
                        System.out.print(tempNode.getAttributes().getNamedItem("name").getTextContent() + " :  \t");
                    }
                } else if (tempNode.getNodeName().startsWith("literal")) {
                    System.out.println(tempNode.getTextContent());
                    System.out.println("");
                } else if (tempNode.getNodeName().startsWith("hasPotColumnNumberOverall")) {
                    System.out.println("Lane" + ": " + tempNode.getTextContent());
                } else if (tempNode.getNodeName().startsWith("hasPotPositionTray")) {
                    System.out.println("Position" + ": " + tempNode.getTextContent());
                } else {
                    //System.out.println(tempNode.getNodeName() + ": " + tempNode.getTextContent());
                }

                if (tempNode.hasChildNodes()) {
                    // loop again if has child node

                    printNote3(tempNode.getChildNodes());
                    //System.out.println("");

                }

            }

        }

    }

    private static void printNote2(NodeList nodeList, int prevValue) {

        for (int count = 0; count < nodeList.getLength(); count++) {

            Node tempNode = nodeList.item(count);

            // make sure it's element node.
            if (tempNode.getNodeType() == Node.ELEMENT_NODE) {

                // get node name and value
                if (!tempNode.getNodeName().startsWith("rdf:") && tempNode.getTextContent().length() > 0) {
                    if (tempNode.getNodeName().startsWith("rdfs:label")) {

                        System.out.println("Name" + ": " + tempNode.getTextContent());
                    } else if (tempNode.getNodeName().startsWith("rdfs:comment")) {
                        System.out.println("Description" + ": " + tempNode.getTextContent());
                    } else if (tempNode.getNodeName().startsWith("hasPotColumnNumberOverall")) {
                        System.out.println("Lane" + ": " + tempNode.getTextContent());
                    } else if (tempNode.getNodeName().startsWith("hasPotPositionTray")) {
                        System.out.println("Position" + ": " + tempNode.getTextContent());
                    } else if (tempNode.getNodeName().startsWith("hasValue")) {
                        //if 
                        //prevValue = Integer.parseInt(tempNode.getNodeValue());
                    } else {
                        System.out.println(tempNode.getNodeName() + ": " + tempNode.getTextContent());
                    }

                }

                if (tempNode.hasChildNodes()) {
                    // loop again if has child node

                    printNote(tempNode.getChildNodes());
                    System.out.println("");

                }

            }

        }
    }

    @Override
    public Model downloadArtifact(final InferredOWLOntologyID artifactId) throws PoddException {
        try {
            final Path tempFile = Files.createTempFile("downloadartifact-", ".rj");
            try (final OutputStream output = Files.newOutputStream(tempFile);) {
                this.downloadArtifact(artifactId, output, RDFFormat.RDFJSON);
            }
            try (final InputStream input = Files.newInputStream(tempFile);) {
                return Rio.parse(input, "", RDFFormat.RDFJSON);
            }
        } catch (RDFParseException | UnsupportedRDFormatException | IOException e) {
            System.out.println(e.toString());
        }
        return null;
    }

    @Override
    public void downloadArtifact(final InferredOWLOntologyID artifactId, final OutputStream outputStream,
            final RDFFormat format) throws PoddException {
        Objects.requireNonNull(artifactId);
        Objects.requireNonNull(outputStream);
        Objects.requireNonNull(format);

        this.log.debug("cookies: {}", this.currentCookies);

        final ClientResource resource = new ClientResource(this.getUrl(PoddWebConstants.PATH_ARTIFACT_GET_BASE));
        resource.getCookies().addAll(this.currentCookies);

        resource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_IDENTIFIER,
                artifactId.getOntologyIRI().toString());

        if (artifactId.getVersionIRI() != null) {
            // FIXME: Versions are not supported in general by PODD, but they are important for
            // verifying the state of the client to allow for early failure in cases where the
            // client is out of date.
            resource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_VERSION_IDENTIFIER,
                    artifactId.getVersionIRI().toString());
        }

        // Pass the desired format to the get method of the ClientResource
        final Representation get = resource.get(MediaType.valueOf(format.getDefaultMIMEType()));

        try {
            get.write(outputStream);
        } catch (final IOException e) {

        }
    }

    @Override
    public Model getObjectByURI(final URI objectURI, final Collection<InferredOWLOntologyID> artifacts)
            throws PoddException {
        final String queryString = String.format(PoddClient.TEMPLATE_SPARQL_BY_URI,
                RenderUtils.getSPARQLQueryString(objectURI));
        this.log.debug("queryString={}", queryString);
        return this.doSPARQL(queryString, artifacts);
    }

    @Override
    public Model getObjectsByType(final URI type, final Collection<InferredOWLOntologyID> artifacts)
            throws PoddException {
        final String queryString = String.format(PoddClient.TEMPLATE_SPARQL_BY_TYPE_WITH_LABEL,
                RenderUtils.getSPARQLQueryString(type));
        this.log.debug("queryString={}", queryString);
        return this.doSPARQL(queryString, artifacts);
    }

    @Override
    public Model getObjectsByTypeAndPrefix(final URI type, final String labelPrefix,
            final Collection<InferredOWLOntologyID> artifacts) throws PoddException {
        final String queryString = String.format(PoddClient.TEMPLATE_SPARQL_BY_TYPE_LABEL_STRSTARTS,
                RenderUtils.escape(labelPrefix), RenderUtils.getSPARQLQueryString(type));
        this.log.debug("queryString={}", queryString);
        return this.doSPARQL(queryString, artifacts);
    }

    @Override
    public Model getObjectsByPredicate(final URI predicate, final Collection<InferredOWLOntologyID> artifacts)
            throws PoddException {
        final String predicateString = RenderUtils.getSPARQLQueryString(predicate);
        // NOTE: predicateString must be both the second and third arguments sent into String.format
        // as it is used twice, once for the Construct and once for the Where
        // Hypothetically the second could be different to the third for mapping predicates, but
        // that would cause confusion if not obvious
        final String queryString = String.format(PoddClient.TEMPLATE_SPARQL_BY_PREDICATE, predicateString,
                predicateString);
        this.log.debug("queryString={}", queryString);
        return this.doSPARQL(queryString, artifacts);
    }

    @Override
    public Model getObjectsByTypePredicateAndPrefix(final URI type, final URI predicate, final String labelPrefix,
            final Collection<InferredOWLOntologyID> artifacts) throws PoddException {
        final String predicateString = RenderUtils.getSPARQLQueryString(predicate);
        // NOTE: predicateString must be both the second and third arguments sent into String.format
        // as it is used twice, once for the Construct and once for the Where
        // Hypothetically the second could be different to the third for mapping predicates, but
        // that would cause confusion if not obvious
        final String queryString = String.format(PoddClient.TEMPLATE_SPARQL_BY_TYPE_LABEL_STRSTARTS_PREDICATE,
                predicateString, predicateString, RenderUtils.escape(labelPrefix),
                RenderUtils.getSPARQLQueryString(type));
        this.log.debug("queryString={}", queryString);
        return this.doSPARQL(queryString, artifacts);
    }

    @Override
    public Model getObjectsByTypeAndBarcode(final URI type, final String barcode,
            final Collection<InferredOWLOntologyID> artifacts) throws PoddException {
        final String queryString = String.format(PoddClient.TEMPLATE_SPARQL_BY_BARCODE_STRSTARTS,
                RenderUtils.escape(barcode), RenderUtils.getSPARQLQueryString(type));
        this.log.debug("queryString={}", queryString);
        return this.doSPARQL(queryString, artifacts);
    }

    @Override
    public Model getAllBarcodes(final Collection<InferredOWLOntologyID> artifacts) {
        try {
            return this.doSPARQL(PoddClient.TEMPLATE_SPARQL_BY_BARCODE_MATCH_NO_TYPE_NO_BARCODE, artifacts);
        } catch (PoddException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public Model getObjectsByBarcode(final String barcode, final Collection<InferredOWLOntologyID> artifacts)
            throws PoddException {
        final String queryString = String.format(PoddClient.TEMPLATE_SPARQL_BY_BARCODE_MATCH_NO_TYPE,
                RenderUtils.escape(barcode));
        this.log.debug("queryString={}", queryString);
        return this.doSPARQL(queryString, artifacts);
    }

    @Override
    public Model getObjectsByTypeAndParent(final URI parent, final URI parentPredicate, final URI type,
            final Collection<InferredOWLOntologyID> artifacts) throws PoddException {
        final String queryString = String.format(PoddClient.TEMPLATE_SPARQL_BY_TYPE_AND_PARENT_ALL_PROPERTIES,
                RenderUtils.getSPARQLQueryString(parent), RenderUtils.getSPARQLQueryString(parentPredicate),
                RenderUtils.getSPARQLQueryString(type));
        this.log.debug("queryString={}", queryString);
        return this.doSPARQL(queryString, artifacts);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.github.podd.client.api.PoddClient#getPoddServerUrl()
     */
    @Override
    public String getPoddServerUrl() {
        String result = this.serverUrl;
        if (result == null) {
            synchronized (this) {
                result = this.serverUrl;
                if (result == null) {
                    this.serverUrl = this.props.get(RestletPoddClientImpl.PROP_PODD_SERVER_URL,
                            RestletPoddClientImpl.DEFAULT_PODD_SERVER_URL);
                }
                result = this.serverUrl;
            }
        }
        return result;
    }

    public PropertyUtil getProps() {
        return this.props;
    }

    public URI getTempURI(final String tempUriString) {
        return RestletPoddClientImpl.vf
                .createURI(RestletPoddClientImpl.TEMP_UUID_PREFIX + tempUriString + UUID.randomUUID().toString());
    }

    /**
     * Creates the URL for a given path using the current {@link #getPoddServerUrl()} result, or
     * throws an IllegalStateException if the server URL has not been set.
     *
     * @param path
     *            The path of the web service to get a full URL for.
     * @return The full URL to the given path.
     * @throws IllegalStateException
     *             If {@link #setPoddServerUrl(String)} has not been called with a valid URL before
     *             this point.
     */
    private String getUrl(final String path) {
        if (this.getPoddServerUrl() == null) {
            throw new IllegalStateException("PODD Server URL has not been set for this client");
        }

        if (path == null || path.isEmpty()) {
            throw new NullPointerException("Path cannot be null or empty");
        }

        String actualPath = path;

        final boolean serverUrlEndsWithSlash = this.serverUrl.endsWith("/");

        // Avoid double slashes
        if (actualPath.startsWith("/") && serverUrlEndsWithSlash) {
            actualPath = actualPath.substring(1);
        } else if (!serverUrlEndsWithSlash) {
            actualPath = "/" + actualPath;
        }

        final String result = this.serverUrl + actualPath;

        this.log.debug("getURL={}", result);

        return result;
    }

    @Override
    public boolean isLoggedIn() {
        return !this.currentCookies.isEmpty();
    }

    @Override
    public Map<RestletUtilRole, Collection<String>> listRoles(final InferredOWLOntologyID artifactId)
            throws PoddException {
        final ClientResource resource = new ClientResource(this.getUrl(PoddWebConstants.PATH_ARTIFACT_ROLES));
        resource.getCookies().addAll(this.currentCookies);
        resource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_IDENTIFIER,
                artifactId.getOntologyIRI().toString());

        this.log.debug("cookies: {}", this.currentCookies);

        final Representation get = resource.get(MediaType.APPLICATION_RDF_TURTLE);

        try {
            return PoddRoles.extractRoleMappingsArtifact(this.parseRdf(get));
        } catch (final IOException e) {
            System.out.println(e.toString());
        }
        return null;
    }

    @Override
    public Map<RestletUtilRole, Collection<URI>> listRoles(final String userIdentifier) throws PoddException {
        final ClientResource resource = new ClientResource(this.getUrl(PoddWebConstants.PATH_USER_ROLES));
        resource.getCookies().addAll(this.currentCookies);
        if (userIdentifier != null) {
            resource.addQueryParameter(PoddWebConstants.KEY_USER_IDENTIFIER, userIdentifier);
        }

        this.log.debug("cookies: {}", this.currentCookies);

        final Representation get = resource.get(MediaType.APPLICATION_RDF_TURTLE);

        try {
            return PoddRoles.extractRoleMappingsUser(this.parseRdf(get));
        } catch (final IOException e) {
            System.out.println(e.toString());
        }
        return null;
    }

    @Override
    public List<PoddUser> listUsers() throws PoddException {
        // Implement this when the service is available
        throw new RuntimeException("TODO: Implement listUsers!");
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.github.podd.client.api.PoddClient#login(java.lang.String, char[])
     */
    @Override
    public boolean login(final String username, final String password) throws PoddException {

        final ClientResource resource = new ClientResource(this.getUrl(PoddWebConstants.DEF_PATH_LOGIN_SUBMIT));
        //final ClientResource resource = new ClientResource("https://poddtest.plantphenomics.org.au/podd/login");

        resource.getCookies().addAll(this.currentCookies);

        // TODO: when Cookies natively supported by Client Resource, or another method remove this
        // Until then, this is necessary to manually attach the cookies after login to the
        // redirected address.
        // GitHub issue for this: https://github.com/restlet/restlet-framework-java/issues/21
        resource.setFollowingRedirects(false);

        final Form form = new Form();
        form.add("username", username);
        form.add("password", password);

        try {
            final Representation rep = resource.post(form.getWebRepresentation(CharacterSet.UTF_8));

            if (rep != null) {
                // FIXME: Representation.getText may be implemented badly, so avoid calling it
                this.log.debug("login result: {}", rep.getText());
            } else {
                this.log.debug("login result was null");
            }

            // HACK
            if (resource.getStatus().equals(Status.REDIRECTION_SEE_OTHER) || resource.getStatus().isSuccess()) {
                this.currentCookies = resource.getCookieSettings();
            }

            this.log.debug("cookies: {}", this.currentCookies);

            return !this.currentCookies.isEmpty();
        } catch (final Throwable e) {
            this.currentCookies.clear();
            System.out.println("");
            System.out.println("Error: Unable to login to server " + this.serverUrl
                    + " with login credentials provided in ~/poddclient.properties, incorrect username or password.");
            System.out.println("");
            System.out.println("");
            this.log.warn("Error with request", e);
        }
        return false;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.github.podd.client.api.PoddClient#logout()
     */
    @Override
    public boolean logout() throws PoddException {
        this.log.debug("cookies: {}", this.currentCookies);

        final ClientResource resource = new ClientResource(this.getUrl(PoddWebConstants.DEF_PATH_LOGOUT));
        // add the cookie settings so that the server knows who to logout
        resource.getCookies().addAll(this.currentCookies);

        // TODO: when Cookies natively supported by Client Resource, or another method remove this
        // Until then, this is necessary to manually attach the cookies after login to the
        // redirected address.
        // GitHub issue for this: https://github.com/restlet/restlet-framework-java/issues/21
        resource.setFollowingRedirects(false);

        final Representation rep = resource.get();

        this.currentCookies = resource.getCookieSettings();

        try {
            this.log.info("logout result status: {}", resource.getStatus());

            if (rep != null) {
                // FIXME: Representation.getText may be implemented badly, so avoid calling it
                // this.log.info("logout result: {}", rep.getText());
            } else {
                this.log.info("logout result was null");
            }

            this.log.info("cookies: {}", this.currentCookies);

            this.currentCookies.clear();

            return true;
        } catch (final Throwable e) {
            this.log.warn("Error with request", e);

        }
        return false;
    }

    private Model parseRdf(final Representation rep) throws PoddException, IOException {
        final RDFFormat format = Rio.getParserFormatForMIMEType(rep.getMediaType().getName());

        /* if(format == null)
        {
        throw new PoddException("Did not understand the format for the RDF response: "
                + rep.getMediaType().getName());
        } */

        try {
            return Rio.parse(rep.getStream(), "", format);
        } catch (RDFParseException | UnsupportedRDFormatException e) {
            System.out.println(e.toString());
        }
        return null;
    }

    /**
     * @param resource
     * @param rdf
     * @return
     * @throws PoddException
     * @throws ResourceException
     */
    private Representation postRdf(final ClientResource resource, final Model rdf)
            throws PoddException, ResourceException {
        final StringWriter writer = new StringWriter();

        try {
            Rio.write(rdf, writer, RDFFormat.RDFJSON);
        } catch (final RDFHandlerException e) {

        }

        final Representation rep = new ReaderRepresentation(new StringReader(writer.toString()),
                RestletUtilMediaType.APPLICATION_RDF_JSON);

        final Representation post = resource.post(rep, RestletUtilMediaType.APPLICATION_RDF_JSON);
        return post;
    }

    @Override
    public InferredOWLOntologyID publishArtifact(final InferredOWLOntologyID ontologyIRI) throws PoddException {
        throw new RuntimeException("TODO: Implement publishArtifact!");
    }

    @Override
    public void removeRole(final String userIdentifier, final RestletUtilRole role,
            final InferredOWLOntologyID artifact) throws PoddException {
        this.log.debug("cookies: {}", this.currentCookies);

        final ClientResource resource = new ClientResource(this.getUrl(PoddWebConstants.PATH_USER_ROLES));
        resource.getCookies().addAll(this.currentCookies);
        resource.addQueryParameter(PoddWebConstants.KEY_USER_IDENTIFIER, userIdentifier);
        resource.addQueryParameter(PoddWebConstants.KEY_DELETE, "true");

        final Map<RestletUtilRole, Collection<URI>> mappings = new HashMap<>();
        final Collection<URI> artifacts = Arrays.asList(artifact.getOntologyIRI().toOpenRDFURI());
        mappings.put(role, artifacts);

        final Model model = new LinkedHashModel();
        PoddRoles.dumpRoleMappingsUser(mappings, model);

        final Representation post = this.postRdf(resource, model);

        try {
            final Model parsedStatements = this.parseRdf(post);

            if (!parsedStatements.contains(null, SesameRealmConstants.OAS_USERIDENTIFIER,
                    PODD.VF.createLiteral(userIdentifier))) {
                this.log.warn("Role edit response did not seem to contain the user identifier");
            }
        } catch (final IOException e) {

        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.github.podd.client.api.PoddClient#setPoddServerUrl(java.lang.String)
     */
    @Override
    public void setPoddServerUrl(final String serverUrl) {
        this.serverUrl = serverUrl;
    }

    public void setProps(final PropertyUtil props) {
        this.props = props;
    }

    @Override
    public InferredOWLOntologyID unpublishArtifact(final InferredOWLOntologyID ontologyIRI) throws PoddException {
        throw new RuntimeException("TODO: Implement unpublishArtifact");
    }

    @Override
    public InferredOWLOntologyID updateArtifact(final InferredOWLOntologyID ontologyIRI,
            final InputStream fullInputStream, final RDFFormat format) throws PoddException {
        throw new RuntimeException("TODO: Implement updateArtifact");
    }

    @Override
    public InferredOWLOntologyID uploadNewArtifact(final Model model) throws PoddException {
        final ByteArrayOutputStream output = new ByteArrayOutputStream();
        try {
            Rio.write(model, output, RDFFormat.RDFJSON);
        } catch (final RDFHandlerException e) {

        }

        return this.uploadNewArtifact(new ByteArrayInputStream(output.toByteArray()), RDFFormat.RDFJSON,
                DanglingObjectPolicy.REPORT, DataReferenceVerificationPolicy.DO_NOT_VERIFY);
    }

    @Override
    public InferredOWLOntologyID uploadNewArtifact(final InputStream input, final RDFFormat format)
            throws PoddException {
        return this.uploadNewArtifact(input, format, DanglingObjectPolicy.REPORT,
                DataReferenceVerificationPolicy.DO_NOT_VERIFY);
    }

    @Override
    public InferredOWLOntologyID uploadNewArtifact(final InputStream input, final RDFFormat format,
            final DanglingObjectPolicy danglingObjectPolicy,
            final DataReferenceVerificationPolicy dataReferenceVerificationPolicy) throws PoddException {
        final InputRepresentation rep = new InputRepresentation(input,
                MediaType.valueOf(format.getDefaultMIMEType()));

        final ClientResource resource = new ClientResource(this.getUrl(PoddWebConstants.PATH_ARTIFACT_UPLOAD));
        resource.getCookies().addAll(this.currentCookies);

        this.log.debug("cookies: {}", this.currentCookies);

        resource.addQueryParameter("format", format.getDefaultMIMEType());
        if (danglingObjectPolicy == DanglingObjectPolicy.FORCE_CLEAN) {
            resource.addQueryParameter(PoddWebConstants.KEY_EDIT_WITH_FORCE, "true");
        }
        if (dataReferenceVerificationPolicy == DataReferenceVerificationPolicy.VERIFY) {
            resource.addQueryParameter(PoddWebConstants.KEY_EDIT_VERIFY_FILE_REFERENCES, "true");
        }

        // Request the results in Turtle to reduce the bandwidth
        final Representation post = resource.post(rep, MediaType.APPLICATION_RDF_TURTLE);

        try {
            final Model parsedStatements = this.parseRdf(post);

            final Collection<InferredOWLOntologyID> result = OntologyUtils.modelToOntologyIDs(parsedStatements,
                    true, false);

            if (!result.isEmpty()) {
                return result.iterator().next();
            }

        } catch (final IOException e) {
            System.out.println(e.toString());
        }
        return null;
    }

    @Override
    public Model doSPARQL(String queryString, Collection<InferredOWLOntologyID> artifacts) throws PoddException {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub

    }

}