org.mycore.restapi.v1.utils.MCRRestAPIObjectsHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.mycore.restapi.v1.utils.MCRRestAPIObjectsHelper.java

Source

/*
 * $Revision: 29635 $ $Date: 2014-04-10 10:55:06 +0200 (Do, 10 Apr 2014) $
 *
 * This file is part of ***  M y C o R e  ***
 * See http://www.mycore.de/ for details.
 *
 * This program is free software; you can use it, redistribute it
 * and / or modify it under the terms of the GNU General Public License
 * (GPL) as published by the Free Software Foundation; either version 2
 * 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program, in a file called gpl.txt or license.txt.
 * If not, write to the Free Software Foundation Inc.,
 * 59 Temple Place - Suite 330, Boston, MA  02111-1307 USA
 */

package org.mycore.restapi.v1.utils;

import java.io.IOException;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.DirectoryStream;
import java.nio.file.FileVisitOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Collectors;

import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.UriInfo;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocumentList;
import org.jdom2.Comment;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.filter.Filters;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import org.jdom2.xpath.XPathExpression;
import org.jdom2.xpath.XPathFactory;
import org.mycore.common.MCRConstants;
import org.mycore.common.MCRException;
import org.mycore.common.config.MCRConfiguration;
import org.mycore.datamodel.common.MCRObjectIDDate;
import org.mycore.datamodel.common.MCRXMLMetadataManager;
import org.mycore.datamodel.metadata.MCRDerivate;
import org.mycore.datamodel.metadata.MCRMetaLinkID;
import org.mycore.datamodel.metadata.MCRMetadataManager;
import org.mycore.datamodel.metadata.MCRObject;
import org.mycore.datamodel.metadata.MCRObjectID;
import org.mycore.datamodel.niofs.MCRPath;
import org.mycore.datamodel.niofs.MCRPathXML;
import org.mycore.frontend.jersey.MCRJerseyUtil;
import org.mycore.restapi.v1.MCRRestAPIObjects;
import org.mycore.restapi.v1.errors.MCRRestAPIError;
import org.mycore.restapi.v1.errors.MCRRestAPIException;
import org.mycore.restapi.v1.errors.MCRRestAPIFieldError;
import org.mycore.restapi.v1.utils.MCRRestAPISortObject.SortOrder;
import org.mycore.solr.MCRSolrClientFactory;

import com.google.gson.stream.JsonWriter;

/**
 * main utility class that handles REST requests
 * 
 * @author Robert Stephan
 * 
 * @version $Revision: $ $Date: $
 */
public class MCRRestAPIObjectsHelper {
    private static Logger LOGGER = LogManager.getLogger(MCRRestAPIObjectsHelper.class);

    private static SimpleDateFormat SDF_UTC = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);

    public static Response showMCRObject(String pathParamId, String queryParamStyle, UriInfo info) {
        try {
            MCRObject mcrObj = retrieveMCRObject(pathParamId);
            Document doc = mcrObj.createXML();
            Element eStructure = doc.getRootElement().getChild("structure");
            if (queryParamStyle != null && !MCRRestAPIObjects.STYLE_DERIVATEDETAILS.equals(queryParamStyle)) {
                throw new MCRRestAPIException(MCRRestAPIError.create(Response.Status.BAD_REQUEST,
                        "The value of parameter {style} is not allowed.",
                        "Allowed values for {style} parameter are: " + MCRRestAPIObjects.STYLE_DERIVATEDETAILS));
            }

            if (MCRRestAPIObjects.STYLE_DERIVATEDETAILS.equals(queryParamStyle) && eStructure != null) {
                Element eDerObjects = eStructure.getChild("derobjects");
                if (eDerObjects != null) {
                    for (Element eDer : (List<Element>) eDerObjects.getChildren("derobject")) {
                        String derID = eDer.getAttributeValue("href", MCRConstants.XLINK_NAMESPACE);
                        try {
                            MCRDerivate der = MCRMetadataManager
                                    .retrieveMCRDerivate(MCRObjectID.getInstance(derID));
                            eDer.addContent(der.createXML().getRootElement().detach());

                            //<mycorederivate xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:noNamespaceSchemaLocation="datamodel-derivate.xsd" ID="cpr_derivate_00003760" label="display_image" version="1.3">
                            //  <derivate display="true">

                            eDer = eDer.getChild("mycorederivate").getChild("derivate");
                            eDer.addContent(listDerivateContent(mcrObj,
                                    MCRMetadataManager.retrieveMCRDerivate(MCRObjectID.getInstance(derID)), info));
                        } catch (MCRException e) {
                            eDer.addContent(new Comment("Error: Derivate not found."));
                        } catch (IOException e) {
                            eDer.addContent(
                                    new Comment("Error: Derivate content could not be listed: " + e.getMessage()));
                        }
                    }
                }
            }

            StringWriter sw = new StringWriter();
            XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
            try {
                outputter.output(doc, sw);
            } catch (IOException e) {
                throw new MCRRestAPIException(MCRRestAPIError.create(Response.Status.INTERNAL_SERVER_ERROR,
                        "Unable to retrieve MyCoRe object", e.getMessage()));
            }
            return Response.ok(sw.toString()).type("application/xml").build();
        }

        catch (MCRRestAPIException rae) {
            return rae.getError().createHttpResponse();
        }

    }

    public static Response showMCRDerivate(String pathParamMcrID, String pathParamDerID, UriInfo info)
            throws IOException {
        try {
            MCRObject mcrObj = retrieveMCRObject(pathParamMcrID);
            MCRDerivate derObj = retrieveMCRDerivate(mcrObj, pathParamDerID);

            Document doc = derObj.createXML();
            doc.getRootElement().addContent(listDerivateContent(mcrObj, derObj, info));

            StringWriter sw = new StringWriter();
            XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
            outputter.output(doc, sw);

            return Response.ok(sw.toString()).type("application/xml").build();

        } catch (MCRRestAPIException e) {
            return e.getError().createHttpResponse();
        }

        // return MCRRestAPIError.create(Response.Status.INTERNAL_SERVER_ERROR, "Unexepected program flow termination.",
        //       "Please contact a developer!").createHttpResponse();
    }

    private static Element listDerivateContent(MCRObject mcrObj, MCRDerivate derObj, UriInfo info)
            throws IOException {
        return listDerivateContent(mcrObj, derObj, "", info);
    }

    private static Element listDerivateContent(MCRObject mcrObj, MCRDerivate derObj, String deriPath, UriInfo info)
            throws IOException {
        Element eContents = new Element("contents");
        eContents.setAttribute("mycoreobject", mcrObj.getId().toString());
        eContents.setAttribute("derivate", derObj.getId().toString());
        if (!deriPath.endsWith("/")) {
            deriPath += "/";
        }
        MCRPath p = MCRPath.getPath(derObj.getId().toString(), deriPath);
        if (p != null) {
            eContents.addContent(MCRPathXML.getDirectoryXML(p).getRootElement().detach());
        }

        String baseURL = MCRJerseyUtil.getBaseURL(info)
                + MCRConfiguration.instance().getString("MCR.RestAPI.v1.Files.URL.path");
        baseURL = baseURL.replace("${mcrid}", mcrObj.getId().toString()).replace("${derid}",
                derObj.getId().toString());
        XPathExpression<Element> xp = XPathFactory.instance().compile(".//child[@type='file']", Filters.element());
        for (Element e : xp.evaluate(eContents)) {
            String uri = e.getChildText("uri");
            if (uri != null) {
                int pos = uri.lastIndexOf(":/");
                String path = uri.substring(pos + 2);
                while (path.startsWith("/")) {
                    path = path.substring(1);
                }
                e.setAttribute("href", baseURL + path);
            }
        }
        return eContents;
    }

    private static String listDerivateContentAsJson(MCRDerivate derObj, String path, int depth, UriInfo info)
            throws IOException {
        StringWriter sw = new StringWriter();
        MCRPath root = MCRPath.getPath(derObj.getId().toString(), "/");
        root = MCRPath.toMCRPath(root.resolve(path));
        if (depth == -1) {
            depth = Integer.MAX_VALUE;
        }
        if (root != null) {
            JsonWriter writer = new JsonWriter(sw);
            Files.walkFileTree(root, EnumSet.noneOf(FileVisitOption.class), depth,
                    new MCRJSONFileVisitor(writer, derObj.getOwnerID(), derObj.getId(), info));
            writer.close();
        }
        return sw.toString();
    }

    /**
     * @see MCRRestAPIObjects#listObjects(UriInfo, String, String, String)
     */
    public static Response listObjects(UriInfo info, String format, String filter, String sort) {
        //analyze sort
        MCRRestAPIError error = MCRRestAPIError.create(Response.Status.BAD_REQUEST,
                "The syntax of one or more query parameters is wrong.", null);

        MCRRestAPISortObject sortObj = null;
        try {
            sortObj = createSortObject(sort);
        } catch (MCRRestAPIException rae) {
            for (MCRRestAPIFieldError fe : rae.getError().getFieldErrors()) {
                error.addFieldError(fe);
            }
        }

        //analyze format

        if (format.equals(MCRRestAPIObjects.FORMAT_JSON) || format.equals(MCRRestAPIObjects.FORMAT_XML)) {
            //ok
        } else {
            error.addFieldError(
                    MCRRestAPIFieldError.create("format", "Allowed values for format are 'json' or 'xml'."));
        }

        //analyze filter
        List<String> projectIDs = new ArrayList<String>();
        List<String> typeIDs = new ArrayList<String>();
        String lastModifiedBefore = null;
        String lastModifiedAfter = null;
        if (filter != null) {
            for (String s : filter.split(";")) {
                if (s.startsWith("project:")) {
                    projectIDs.add(s.substring(8));
                    continue;
                }
                if (s.startsWith("type:")) {
                    typeIDs.add(s.substring(5));
                    continue;
                }
                if (s.startsWith("lastModifiedBefore:")) {
                    if (!validateDateInput(s.substring(19))) {
                        error.addFieldError(MCRRestAPIFieldError.create("filter",
                                "The value of lastModifiedBefore could not be parsed. Please use UTC syntax: yyyy-MM-dd'T'HH:mm:ss'Z'."));
                        continue;
                    }
                    if (lastModifiedBefore == null) {
                        lastModifiedBefore = s.substring(19);
                    } else if (s.substring(19).compareTo(lastModifiedBefore) < 0) {
                        lastModifiedBefore = s.substring(19);
                    }
                    continue;
                }

                if (s.startsWith("lastModifiedAfter:")) {
                    if (!validateDateInput(s.substring(18))) {
                        error.addFieldError(MCRRestAPIFieldError.create("filter",
                                "The value of lastModifiedAfter could not be parsed. Please use UTC syntax: yyyy-MM-dd'T'HH:mm:ss'Z'."));
                        continue;
                    }
                    if (lastModifiedAfter == null) {
                        lastModifiedAfter = s.substring(18);
                    } else if (s.substring(18).compareTo(lastModifiedAfter) > 0) {
                        lastModifiedAfter = s.substring(18);
                    }
                    continue;
                }

                error.addFieldError(MCRRestAPIFieldError.create("filter", "The syntax of the filter '" + s
                        + "'could not be parsed. The syntax should be [filterName]:[value]. Allowed filterNames are 'project', 'type', 'lastModifiedBefore' and 'lastModifiedAfter'."));
            }
        }

        if (error.getFieldErrors().size() > 0) {
            return error.createHttpResponse();
        }

        //Parameters are checked - continue tor retrieve data

        //retrieve MCRIDs by Type and Project ID
        Set<String> mcrIDs = new HashSet<String>();
        if (projectIDs.isEmpty()) {
            if (typeIDs.isEmpty()) {
                mcrIDs = MCRXMLMetadataManager.instance().listIDs().stream()
                        .filter(id -> !id.contains("_derivate_")).collect(Collectors.toSet());
            } else {
                for (String t : typeIDs) {
                    mcrIDs.addAll(MCRXMLMetadataManager.instance().listIDsOfType(t));
                }
            }
        } else {

            if (typeIDs.isEmpty()) {
                for (String id : MCRXMLMetadataManager.instance().listIDs()) {
                    String[] split = id.split("_");
                    if (!split[1].equals("derivate") && projectIDs.contains(split[0])) {
                        mcrIDs.add(id);
                    }
                }
            } else {
                for (String p : projectIDs) {
                    for (String t : typeIDs) {
                        mcrIDs.addAll(MCRXMLMetadataManager.instance().listIDsForBase(p + "_" + t));
                    }
                }
            }
        }

        //Filter by modifiedBefore and modifiedAfter
        List<String> l = new ArrayList<String>();
        l.addAll(mcrIDs);
        List<MCRObjectIDDate> objIdDates = new ArrayList<MCRObjectIDDate>();
        try {
            objIdDates = MCRXMLMetadataManager.instance().retrieveObjectDates(l);
        } catch (IOException e) {
            //TODO
        }
        if (lastModifiedAfter != null || lastModifiedBefore != null) {
            List<MCRObjectIDDate> testObjIdDates = objIdDates;
            objIdDates = new ArrayList<MCRObjectIDDate>();
            for (MCRObjectIDDate oid : testObjIdDates) {
                String test = SDF_UTC.format(oid.getLastModified());
                if (lastModifiedAfter != null && test.compareTo(lastModifiedAfter) < 0)
                    continue;
                if (lastModifiedBefore != null
                        && lastModifiedBefore.compareTo(test.substring(0, lastModifiedBefore.length())) < 0)
                    continue;
                objIdDates.add(oid);
            }
        }

        //sort if necessary
        if (sortObj != null) {
            Collections.sort(objIdDates, new MCRRestAPISortObjectComparator(sortObj));
        }

        //output as XML
        if (MCRRestAPIObjects.FORMAT_XML.equals(format)) {
            Element eMcrobjects = new Element("mycoreobjects");
            Document docOut = new Document(eMcrobjects);
            eMcrobjects.setAttribute("numFound", Integer.toString(objIdDates.size()));
            for (MCRObjectIDDate oid : objIdDates) {
                Element eMcrObject = new Element("mycoreobject");
                eMcrObject.setAttribute("ID", oid.getId());
                eMcrObject.setAttribute("lastModified", SDF_UTC.format(oid.getLastModified()));
                eMcrObject.setAttribute("href", info.getAbsolutePathBuilder().path(oid.getId()).build().toString());

                eMcrobjects.addContent(eMcrObject);
            }
            try {
                StringWriter sw = new StringWriter();
                XMLOutputter xout = new XMLOutputter(Format.getPrettyFormat());
                xout.output(docOut, sw);
                return Response.ok(sw.toString()).type("application/xml; charset=UTF-8").build();
            } catch (IOException e) {
                return MCRRestAPIError.create(Response.Status.INTERNAL_SERVER_ERROR,
                        "A problem occurred while fetching the data", e.getMessage()).createHttpResponse();
            }
        }

        //output as JSON
        if (MCRRestAPIObjects.FORMAT_JSON.equals(format)) {
            StringWriter sw = new StringWriter();
            try {
                JsonWriter writer = new JsonWriter(sw);
                writer.setIndent("    ");
                writer.beginObject();
                writer.name("numFound").value(objIdDates.size());
                writer.name("mycoreobjects");
                writer.beginArray();
                for (MCRObjectIDDate oid : objIdDates) {
                    writer.beginObject();
                    writer.name("ID").value(oid.getId());
                    writer.name("lastModified").value(SDF_UTC.format(oid.getLastModified()));
                    writer.name("href").value(info.getAbsolutePathBuilder().path(oid.getId()).build().toString());
                    writer.endObject();
                }
                writer.endArray();
                writer.endObject();

                writer.close();

                return Response.ok(sw.toString()).type("application/json; charset=UTF-8").build();
            } catch (IOException e) {
                return MCRRestAPIError.create(Response.Status.INTERNAL_SERVER_ERROR,
                        "A problem occurred while fetching the data", e.getMessage()).createHttpResponse();
            }
        }
        return MCRRestAPIError.create(Response.Status.INTERNAL_SERVER_ERROR, "A problem in programm flow", null)
                .createHttpResponse();
    }

    /**
     * @see MCRRestAPIObjects#listDerivates(UriInfo, String, String, String)
     */
    public static Response listDerivates(UriInfo info, String mcrIDString, String format, String sort) {
        //analyze sort
        try {
            MCRRestAPIError error = MCRRestAPIError.create(Response.Status.BAD_REQUEST,
                    "The syntax of one or more query parameters is wrong.", null);

            MCRRestAPISortObject sortObj = null;
            try {
                sortObj = createSortObject(sort);
            } catch (MCRRestAPIException rae) {
                for (MCRRestAPIFieldError fe : rae.getError().getFieldErrors()) {
                    error.addFieldError(fe);
                }
            }

            //analyze format

            if (format.equals(MCRRestAPIObjects.FORMAT_JSON) || format.equals(MCRRestAPIObjects.FORMAT_XML)) {
                //ok
            } else {
                error.addFieldError(
                        MCRRestAPIFieldError.create("format", "Allowed values for format are 'json' or 'xml'."));
            }

            if (error.getFieldErrors().size() > 0) {
                throw new MCRRestAPIException(error);
            }

            //Parameters are checked - continue to retrieve data

            List<MCRObjectIDDate> objIdDates = retrieveMCRObject(mcrIDString).getStructure().getDerivates().stream()
                    .map(MCRMetaLinkID::getXLinkHrefID).filter(MCRMetadataManager::exists).map(id -> {
                        return new MCRObjectIDDate() {
                            long lastModified;
                            {
                                try {
                                    lastModified = MCRXMLMetadataManager.instance().getLastModified(id);
                                } catch (IOException e) {
                                    lastModified = 0;
                                    LOGGER.error("Exception while getting last modified of " + id, e);
                                }
                            }

                            @Override
                            public String getId() {
                                return id.toString();
                            }

                            @Override
                            public Date getLastModified() {
                                return new Date(lastModified);
                            }
                        };
                    }).sorted(new MCRRestAPISortObjectComparator(sortObj)::compare).collect(Collectors.toList());

            //output as XML
            if (MCRRestAPIObjects.FORMAT_XML.equals(format)) {
                Element eDerObjects = new Element("derobjects");
                Document docOut = new Document(eDerObjects);
                eDerObjects.setAttribute("numFound", Integer.toString(objIdDates.size()));
                for (MCRObjectIDDate oid : objIdDates) {
                    Element eDerObject = new Element("derobject");
                    eDerObject.setAttribute("ID", oid.getId());
                    MCRDerivate der = MCRMetadataManager.retrieveMCRDerivate(MCRObjectID.getInstance(oid.getId()));
                    String mcrID = der.getDerivate().getMetaLink().getXLinkHref();
                    eDerObject.setAttribute("metadata", mcrID);
                    if (der.getLabel() != null) {
                        eDerObject.setAttribute("label", der.getLabel());
                    }
                    eDerObject.setAttribute("lastModified", SDF_UTC.format(oid.getLastModified()));
                    eDerObject.setAttribute("href",
                            info.getAbsolutePathBuilder().path(oid.getId()).build().toString());

                    eDerObjects.addContent(eDerObject);
                }
                try {
                    StringWriter sw = new StringWriter();
                    XMLOutputter xout = new XMLOutputter(Format.getPrettyFormat());
                    xout.output(docOut, sw);
                    return Response.ok(sw.toString()).type("application/xml; charset=UTF-8").build();
                } catch (IOException e) {
                    return MCRRestAPIError
                            .create(Response.Status.INTERNAL_SERVER_ERROR,
                                    "A problem occurred while fetching the data", e.getMessage())
                            .createHttpResponse();
                }
            }

            //output as JSON
            if (MCRRestAPIObjects.FORMAT_JSON.equals(format)) {
                StringWriter sw = new StringWriter();
                try {
                    JsonWriter writer = new JsonWriter(sw);
                    writer.setIndent("    ");
                    writer.beginObject();
                    writer.name("numFound").value(objIdDates.size());
                    writer.name("mycoreobjects");
                    writer.beginArray();
                    for (MCRObjectIDDate oid : objIdDates) {
                        writer.beginObject();
                        writer.name("ID").value(oid.getId());
                        MCRDerivate der = MCRMetadataManager
                                .retrieveMCRDerivate(MCRObjectID.getInstance(oid.getId()));
                        String mcrID = der.getDerivate().getMetaLink().getXLinkHref();
                        writer.name("metadata").value(mcrID);
                        if (der.getLabel() != null) {
                            writer.name("label").value(der.getLabel());
                        }
                        writer.name("lastModified").value(SDF_UTC.format(oid.getLastModified()));
                        writer.name("href")
                                .value(info.getAbsolutePathBuilder().path(oid.getId()).build().toString());
                        writer.endObject();
                    }
                    writer.endArray();
                    writer.endObject();

                    writer.close();

                    return Response.ok(sw.toString()).type("application/json; charset=UTF-8").build();
                } catch (IOException e) {
                    throw new MCRRestAPIException(MCRRestAPIError.create(Response.Status.INTERNAL_SERVER_ERROR,
                            "A problem occurred while fetching the data", e.getMessage()));
                }
            }
        } catch (MCRRestAPIException rae) {
            return rae.getError().createHttpResponse();
        }

        return MCRRestAPIError.create(Response.Status.INTERNAL_SERVER_ERROR,
                "Unexepected program flow termination.", "Please contact a developer!").createHttpResponse();
    }

    public static Response listContents(Request request, String mcrIDString, String derIDString, String format,
            String path, int depth, UriInfo info) throws IOException {
        try {

            if (!format.equals(MCRRestAPIObjects.FORMAT_JSON) && !format.equals(MCRRestAPIObjects.FORMAT_XML)) {
                MCRRestAPIError error = MCRRestAPIError.create(Response.Status.BAD_REQUEST,
                        "The syntax of one or more query parameters is wrong.", null);
                error.addFieldError(
                        MCRRestAPIFieldError.create("format", "Allowed values for format are 'json' or 'xml'."));
                throw new MCRRestAPIException(error);
            }
            //TODO: parsing jdom documents is really necessary?
            MCRObject mcrObj = retrieveMCRObject(mcrIDString);
            MCRDerivate derObj = retrieveMCRDerivate(mcrObj, derIDString);

            MCRPath root = MCRPath.getPath(derObj.getId().toString(), "/");
            BasicFileAttributes readAttributes = Files.readAttributes(root, BasicFileAttributes.class);
            Date lastModified = new Date(readAttributes.lastModifiedTime().toMillis());
            ResponseBuilder responseBuilder = request.evaluatePreconditions(lastModified);
            if (responseBuilder != null) {
                return responseBuilder.build();
            }
            switch (format) {
            case MCRRestAPIObjects.FORMAT_XML:
                Document docOut = new Document(listDerivateContent(mcrObj, derObj, path, info));
                try (StringWriter sw = new StringWriter()) {
                    XMLOutputter xout = new XMLOutputter(Format.getPrettyFormat());
                    xout.output(docOut, sw);
                    return response(sw.toString(), "application/xml", lastModified);
                } catch (IOException e) {
                    return MCRRestAPIError
                            .create(Response.Status.INTERNAL_SERVER_ERROR,
                                    "A problem occurred while fetching the data", e.getMessage())
                            .createHttpResponse();
                }
            case MCRRestAPIObjects.FORMAT_JSON:
                if (MCRRestAPIObjects.FORMAT_JSON.equals(format)) {
                    String result = listDerivateContentAsJson(derObj, path, depth, info);
                    return response(result, "application/json", lastModified);
                }
            default:
                return MCRRestAPIError.create(Response.Status.INTERNAL_SERVER_ERROR,
                        "Unexepected program flow termination.", "Please contact a developer!")
                        .createHttpResponse();
            }
        } catch (MCRRestAPIException rae) {
            return rae.getError().createHttpResponse();
        }
    }

    public static String retrieveMaindocURL(String mcrIDString, String derIDString, UriInfo info)
            throws IOException {
        try {
            MCRObject mcrObj = retrieveMCRObject(mcrIDString);
            MCRDerivate derObj = retrieveMCRDerivate(mcrObj, derIDString);
            String maindoc = derObj.getDerivate().getInternals().getMainDoc();

            String baseURL = MCRJerseyUtil.getBaseURL(info)
                    + MCRConfiguration.instance().getString("MCR.RestAPI.v1.Files.URL.path");
            baseURL = baseURL.replace("${mcrid}", mcrObj.getId().toString()).replace("${derid}",
                    derObj.getId().toString());

            return baseURL + maindoc;
        } catch (MCRRestAPIException rae) {
            return null;
        }
    }

    private static Response response(String response, String type, Date lastModified) {
        byte[] responseBytes = response.getBytes(StandardCharsets.UTF_8);
        String mimeType = type + "; charset=UTF-8";
        CacheControl cacheControl = new CacheControl();
        cacheControl.setNoTransform(false);
        cacheControl.setMaxAge(0);
        return Response.ok(responseBytes, mimeType).lastModified(lastModified)
                .header("Content-Length", responseBytes.length).cacheControl(cacheControl).build();
    }

    /**
     * validates the given String if it matches the UTC syntax or the beginning of it
     * @param test
     * @return true, if it is valid
     */
    private static boolean validateDateInput(String test) {
        String base = "0000-00-00T00:00:00Z";
        if (test.length() > base.length())
            return false;
        test = test + base.substring(test.length());
        try {
            SDF_UTC.parse(test);
        } catch (ParseException e) {
            return false;
        }
        return true;
    }

    private static MCRRestAPISortObject createSortObject(String input) throws MCRRestAPIException {
        if (input == null) {
            return null;
        }
        MCRRestAPIError error = MCRRestAPIError.create(Response.Status.BAD_REQUEST, "", null);
        MCRRestAPISortObject result = new MCRRestAPISortObject();

        String[] data = input.split(":");
        if (data.length == 2) {
            result.setField(data[0].replace("|", ""));
            String sortOrder = data[1].toLowerCase(Locale.GERMAN).replace("|", "");
            if (!"ID".equals(result.getField()) && !"lastModified".equals(result.getField())) {
                error.addFieldError(MCRRestAPIFieldError.create("sort",
                        "Allowed values for sortField are 'ID' and 'lastModified'."));
            }

            if ("asc".equals(sortOrder)) {
                result.setOrder(SortOrder.ASC);
            }
            if ("desc".equals(sortOrder)) {
                result.setOrder(SortOrder.DESC);
            }
            if (result.getOrder() == null) {
                error.addFieldError(
                        MCRRestAPIFieldError.create("sort", "Allowed values for sortOrder are 'asc' and 'desc'."));
            }

        } else {
            error.addFieldError(
                    MCRRestAPIFieldError.create("sort", "The syntax should be [sortField]:[sortOrder]."));
        }
        if (error.getFieldErrors().size() > 0) {
            throw new MCRRestAPIException(error);
        }
        return result;
    }

    private static MCRObject retrieveMCRObject(String idString) throws MCRRestAPIException {
        String key = "mcr"; // the default value for the key
        if (idString.contains(":")) {
            int pos = idString.indexOf(":");
            key = idString.substring(0, pos);
            idString = idString.substring(pos + 1);
            if (!key.equals("mcr")) {
                try {
                    idString = URLDecoder.decode(idString, "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    //will not happen
                }
                //ToDo - Shall we restrict the key set with a property?

                //throw new MCRRestAPIException(MCRRestAPIError.create(Response.Status.BAD_REQUEST,
                //        "The ID is not valid.", "The prefix is unkown. Only 'mcr' is allowed."));
            }
        }
        if (key.equals("mcr")) {

            MCRObjectID mcrID = null;
            try {
                mcrID = MCRObjectID.getInstance(idString);
            } catch (Exception e) {
                throw new MCRRestAPIException(MCRRestAPIError.create(Response.Status.BAD_REQUEST,
                        "The MyCoRe ID '" + idString
                                + "' is not valid. Did you use the proper format: '{project}_{type}_{number}'?",
                        e.getMessage()));
            }

            if (!MCRMetadataManager.exists(mcrID)) {
                throw new MCRRestAPIException(MCRRestAPIError.create(Response.Status.NOT_FOUND,
                        "There is no object with the given MyCoRe ID '" + idString + "'.", null));
            }

            return MCRMetadataManager.retrieveMCRObject(mcrID);
        } else {
            SolrClient solrClient = MCRSolrClientFactory.getSolrClient();
            SolrQuery query = new SolrQuery();
            query.setQuery(key + ":" + idString);
            try {
                QueryResponse response = solrClient.query(query);
                SolrDocumentList solrResults = response.getResults();
                if (solrResults.getNumFound() == 1) {
                    String id = solrResults.get(0).getFieldValue("returnId").toString();
                    return retrieveMCRObject(id);
                } else {
                    if (solrResults.getNumFound() == 0) {
                        throw new MCRRestAPIException(MCRRestAPIError.create(Response.Status.NOT_FOUND,
                                "There is no object with the given ID '" + key + ":" + idString + "'.", null));
                    } else {
                        throw new MCRRestAPIException(
                                MCRRestAPIError.create(Response.Status.NOT_FOUND,
                                        "The ID is not unique. There are " + solrResults.getNumFound()
                                                + " objecst fore the given ID '" + key + ":" + idString + "'.",
                                        null));
                    }
                }
            } catch (SolrServerException | IOException e) {
                LOGGER.error(e);
            }
            return null;
        }
    }

    private static MCRDerivate retrieveMCRDerivate(MCRObject mcrObj, String derIDString)
            throws MCRRestAPIException {

        String derKey = "mcr"; // the default value for the key
        if (derIDString.contains(":")) {
            int pos = derIDString.indexOf(":");
            derKey = derIDString.substring(0, pos);
            derIDString = derIDString.substring(pos + 1);
            if (!derKey.equals("mcr") && !derKey.equals("label")) {
                throw new MCRRestAPIException(MCRRestAPIError.create(Response.Status.BAD_REQUEST,
                        "The ID is not valid.", "The prefix is unkown. Only 'mcr' or 'label' are allowed."));
            }
        }

        String matchedDerID = null;
        for (MCRMetaLinkID check : mcrObj.getStructure().getDerivates()) {
            if (derKey.equals("mcr")) {
                if (check.getXLinkHref().equals(derIDString)) {
                    matchedDerID = check.getXLinkHref();
                    break;
                }
            }
            if (derKey.equals("label")) {
                if (derIDString.equals(check.getXLinkLabel()) || derIDString.equals(check.getXLinkTitle())) {
                    matchedDerID = check.getXLinkHref();
                    break;
                }
            }
        }

        if (matchedDerID == null) {
            throw new MCRRestAPIException(MCRRestAPIError.create(Response.Status.NOT_FOUND, "Derivate not found.",
                    "The MyCoRe Object with id '" + mcrObj.getId().toString()
                            + "' does not contain a derivate with id '" + derIDString + "'."));
        }

        MCRObjectID derID = MCRObjectID.getInstance(matchedDerID);
        if (!MCRMetadataManager.exists(derID)) {
            throw new MCRRestAPIException(MCRRestAPIError.create(Response.Status.NOT_FOUND,
                    "There is no derivate with the id '" + matchedDerID + "'.", null));
        }

        return MCRMetadataManager.retrieveMCRDerivate(derID);
    }

    public static boolean hasChildren(Path p) {
        try {
            if (Files.isDirectory(p)) {
                DirectoryStream<Path> ds = Files.newDirectoryStream(p);
                return ds.iterator().hasNext();
            }
        } catch (IOException e) {
            LOGGER.error(e);
        }
        return false;
    }
}