org.eclipse.winery.repository.Utils.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.winery.repository.Utils.java

Source

/*******************************************************************************
 * Copyright (c) 2012-2013 University of Stuttgart.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and the Apache License 2.0 which both accompany this distribution,
 * and are available at http://www.eclipse.org/legal/epl-v10.html
 * and http://www.apache.org/licenses/LICENSE-2.0
 *
 * Contributors:
 *     Oliver Kopp - initial API and implementation
 *******************************************************************************/
package org.eclipse.winery.repository;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.Response.Status.Family;
import javax.ws.rs.core.StreamingOutput;
import javax.ws.rs.core.UriInfo;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.QName;

import org.eclipse.winery.common.RepositoryFileReference;
import org.eclipse.winery.common.Util;
import org.eclipse.winery.common.constants.MimeTypes;
import org.eclipse.winery.common.ids.GenericId;
import org.eclipse.winery.common.ids.Namespace;
import org.eclipse.winery.common.ids.XMLId;
import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId;
import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
import org.eclipse.winery.common.ids.definitions.imports.XSDImportId;
import org.eclipse.winery.model.tosca.Definitions;
import org.eclipse.winery.model.tosca.TArtifactType;
import org.eclipse.winery.model.tosca.TConstraint;
import org.eclipse.winery.model.tosca.TEntityTemplate;
import org.eclipse.winery.model.tosca.TEntityType;
import org.eclipse.winery.model.tosca.TExtensibleElements;
import org.eclipse.winery.model.tosca.TNodeTemplate;
import org.eclipse.winery.model.tosca.TNodeType;
import org.eclipse.winery.model.tosca.TPolicyType;
import org.eclipse.winery.model.tosca.TRelationshipType;
import org.eclipse.winery.model.tosca.TServiceTemplate;
import org.eclipse.winery.model.tosca.TTag;
import org.eclipse.winery.repository.backend.BackendUtils;
import org.eclipse.winery.repository.backend.Repository;
import org.eclipse.winery.repository.datatypes.ids.admin.AdminId;
import org.eclipse.winery.repository.export.CSARExporter;
import org.eclipse.winery.repository.export.TOSCAExportUtil;
import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource;
import org.eclipse.winery.repository.resources.AbstractComponentsResource;
import org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates.ArtifactTemplateResource;
import org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates.ArtifactTemplatesResource;
import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource;
import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypesResource;
import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypeResource;
import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypesResource;
import org.eclipse.winery.repository.resources.imports.xsdimports.XSDImportResource;
import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.core.header.FormDataContentDisposition;
import com.sun.jersey.multipart.FormDataBodyPart;
import org.apache.taglibs.standard.functions.Functions;
import org.apache.tika.detect.Detector;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.xerces.xs.XSConstants;
import org.slf4j.ext.XLogger;
import org.slf4j.ext.XLoggerFactory;
import org.w3c.dom.Element;

/**
 * Contains utility functionality concerning with everything that is
 * <em>not</em> related only to the repository, but more. For instance, resource
 * functionality. Utility functionality for the repository is contained at
 * {@link BackendUtils}
 */
public class Utils {

    private static final XLogger LOGGER = XLoggerFactory.getXLogger(Utils.class);

    public static URI createURI(String uri) {
        try {
            return new URI(uri);
        } catch (URISyntaxException e) {
            LOGGER.error("uri " + uri + " caused an exception", e);
            throw new IllegalStateException();
        }
    }

    // RegExp inspired by http://stackoverflow.com/a/5396246/873282
    // NameStartChar without ":"
    // stackoverflow: -dfff, standard: d7fff
    private static final String RANGE_NCNAMESTARTCHAR = "A-Z_a-z\\u00C0\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02ff\\u0370-\\u037d"
            + "\\u037f-\\u1fff\\u200c\\u200d\\u2070-\\u218f\\u2c00-\\u2fef\\u3001-\\ud7ff"
            + "\\uf900-\\ufdcf\\ufdf0-\\ufffd\\x10000-\\xEFFFF";
    private static final String REGEX_NCNAMESTARTCHAR = "[" + Utils.RANGE_NCNAMESTARTCHAR + "]";

    private static final String RANGE_NCNAMECHAR = Utils.RANGE_NCNAMESTARTCHAR
            + "\\-\\.0-9\\u00b7\\u0300-\\u036f\\u203f-\\u2040";
    private static final String REGEX_INVALIDNCNAMESCHAR = "[^" + Utils.RANGE_NCNAMECHAR + "]";

    /**
     * Creates a (valid) XML ID (NCName) based on the passed name
     *
     * Valid NCNames: http://www.w3.org/TR/REC-xml-names/#NT-NCName /
     * http://www.w3.org/TR/xml/#NT-Name http://www.w3.org/TR/xml/#NT-Name
     *
     */
    public static XMLId createXMLid(String name) {
        return new XMLId(Utils.createXMLidAsString(name), false);
    }

    /**
     * Creates a (valid) XML ID (NCName) based on the passed name
     *
     * Valid NCNames: http://www.w3.org/TR/REC-xml-names/#NT-NCName /
     * http://www.w3.org/TR/xml/#NT-Name http://www.w3.org/TR/xml/#NT-Name
     *
     * TODO: this method seems to be equal to {@link
     * Util#makeNCName(java.lang.String)}. The methods should be
     * merged into one.
     *
     */
    public static String createXMLidAsString(String name) {
        String id = name;
        if (!id.substring(0, 1).matches(Utils.REGEX_NCNAMESTARTCHAR)) {
            id = "_".concat(id);
        }
        // id starts with a valid character

        // before we wipe out all invalid characters, we do a readable
        // replacement for appropriate characters
        id = id.replace(' ', '_');

        // keep length of ID, only wipe out invalid characters
        // alternative: replace invalid characters by URLencoded version. As the
        // ID is visible only in the URL, this quick hack should be OK
        // ID is visible only in the URL, this quick hack should be OK
        id = id.replaceAll(Utils.REGEX_INVALIDNCNAMESCHAR, "_");

        return id;
    }

    /**
     * Returns the plain XML for the selected resource
     */
    public static Response getDefinitionsOfSelectedResource(final AbstractComponentInstanceResource resource,
            final URI uri) {
        final TOSCAExportUtil exporter = new TOSCAExportUtil();
        StreamingOutput so = output -> {
            Map<String, Object> conf = new HashMap<>();
            conf.put(TOSCAExportUtil.ExportProperties.REPOSITORY_URI.toString(), uri);
            try {
                exporter.exportTOSCA(resource.getId(), output, conf);
            } catch (JAXBException e) {
                throw new WebApplicationException(e);
            }
            output.close();
        };
        /*
         * this code is for offering a download action // Browser offers save as
         * // .tosca is more or less needed for debugging, only a CSAR makes
         * sense. // Therefore, we want to have the xml opened in the browser.
         * StringBuilder sb = new StringBuilder();
         * sb.append("attachment;filename=\"");
         * sb.append(resource.getXmlId().getEncoded()); sb.append(" - ");
         * sb.append(resource.getNamespace().getEncoded()); sb.append(".xml");
         * sb.append("\""); return Response.ok().header("Content-Disposition",
         * sb
         * .toString()).type(MediaType.APPLICATION_XML_TYPE).entity(so).build();
         */
        return Response.ok().type(MediaType.APPLICATION_XML).entity(so).build();
    }

    public static Response getCSARofSelectedResource(final AbstractComponentInstanceResource resource) {
        final CSARExporter exporter = new CSARExporter();
        StreamingOutput so = output -> {
            try {
                exporter.writeCSAR(resource.getId(), output);
            } catch (Exception e) {
                throw new WebApplicationException(e);
            }
        };
        StringBuilder sb = new StringBuilder();
        sb.append("attachment;filename=\"");
        sb.append(resource.getXmlId().getEncoded());
        sb.append(org.eclipse.winery.repository.Constants.SUFFIX_CSAR);
        sb.append("\"");
        return Response.ok().header("Content-Disposition", sb.toString()).type(MimeTypes.MIMETYPE_ZIP).entity(so)
                .build();
    }

    /**
     * @return Singular type name for the given resource. E.g.,
     *         "ServiceTemplateResource" gets "ServiceTemplate"
     */
    public static String getTypeForInstance(Class<? extends AbstractComponentInstanceResource> resClass) {
        String res = resClass.getName();
        // Everything between the last "." and before "Resource" is the Type
        int dotIndex = res.lastIndexOf('.');
        assert (dotIndex >= 0);
        return res.substring(dotIndex + 1, res.length() - "Resource".length());
    }

    /**
     * @return Singular type name for the given id. E.g., "ServiceTemplateId"
     *         gets "ServiceTemplate"
     */
    public static String getTypeForAdminId(Class<? extends AdminId> idClass) {
        return Util.getEverythingBetweenTheLastDotAndBeforeId(idClass);
    }

    /**
     * @return Singular type name for given AbstractComponentsResource. E.g,
     *         "ServiceTemplatesResource" gets "ServiceTemplate"
     */
    public static String getTypeForComponentContainer(Class<? extends AbstractComponentsResource> containerClass) {
        String res = containerClass.getName();
        // Everything between the last "." and before "sResource" is the Type
        int dotIndex = res.lastIndexOf('.');
        assert (dotIndex >= 0);
        return res.substring(dotIndex + 1, res.length() - "sResource".length());
    }

    @SuppressWarnings("unchecked")
    public static Class<? extends TOSCAComponentId> getComponentIdClass(String idClassName) {
        String pkg = "org.eclipse.winery.common.ids.definitions.";
        if (idClassName.contains("Import")) {
            // quick hack to handle imports, which reside in their own package
            pkg = pkg + "imports.";
        }
        String fullClassName = pkg + idClassName;
        try {
            return (Class<? extends TOSCAComponentId>) Class.forName(fullClassName);
        } catch (ClassNotFoundException e) {
            // quick hack for Ids local to winery repository
            try {
                fullClassName = "org.eclipse.winery.repository.datatypes.ids.admin." + idClassName;
                return (Class<? extends TOSCAComponentId>) Class.forName(fullClassName);
            } catch (ClassNotFoundException e2) {
                String errorMsg = "Could not find id class for component container, " + fullClassName;
                Utils.LOGGER.error(errorMsg);
                throw new IllegalStateException(errorMsg);
            }
        }
    }

    /**
     * Returns a class object for ids of components nested in the given
     * AbstractComponentsResource
     */
    public static Class<? extends TOSCAComponentId> getComponentIdClassForComponentContainer(
            Class<? extends AbstractComponentsResource> containerClass) {
        // the name of the id class is the type + "Id"
        String idClassName = Utils.getTypeForComponentContainer(containerClass) + "Id";

        return Utils.getComponentIdClass(idClassName);
    }

    public static Class<? extends TOSCAComponentId> getComponentIdClassForTExtensibleElements(
            Class<? extends TExtensibleElements> clazz) {
        // we assume that the clazzName always starts with a T.
        // Therefore, we fetch everything after the last dot (plus offest 1)
        String idClassName = clazz.getName();
        int dotIndex = idClassName.lastIndexOf('.');
        assert (dotIndex >= 0);
        idClassName = idClassName.substring(dotIndex + 2) + "Id";

        return Utils.getComponentIdClass(idClassName);
    }

    private static final String slashEncoded = Util.URLencode("/");

    public static String getURLforPathInsideRepo(String pathInsideRepo) {
        // first encode the whole string
        String res = Util.URLencode(pathInsideRepo);
        // issue: "/" is also encoded. This has to be undone:
        res = res.replaceAll(Utils.slashEncoded, "/");
        return res;
    }

    /**
     * Shared object to map JSONs
     */
    public static final ObjectMapper mapper = new ObjectMapper();

    public static String Object2JSON(Object o) {
        String res;
        try {
            res = Utils.mapper.writeValueAsString(o);
        } catch (Exception e) {
            Utils.LOGGER.error(e.getMessage(), e);
            return null;
        }
        return res;
    }

    @SuppressWarnings("unchecked")
    public static Class<? extends GenericId> getGenericIdClassForType(String typeIdType) {
        Class<? extends GenericId> res;
        // quick hack - we only need definitions right now
        String pkg = "org.eclipse.winery.repository.datatypes.ids.definitions.";
        String className = typeIdType;
        className = pkg + className;
        try {
            res = (Class<? extends GenericId>) Class.forName(className);
        } catch (ClassNotFoundException e) {
            Utils.LOGGER.error("Could not find id class for id type", e);
            res = null;
        }
        return res;
    }

    /**
     * @return the absolute path for the given id
     */
    public static String getAbsoluteURL(GenericId id) {
        return Prefs.INSTANCE.getResourcePath() + "/"
                + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(id));
    }

    /**
     * @param baseURI the URI from which the path should start
     * @param id the generic id to resolve
     *
     * @return the relative path for the given id
     */
    public static String getRelativeURL(URI baseURI, GenericId id) {
        String absolutePath = Prefs.INSTANCE.getResourcePath() + "/"
                + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(id));
        return baseURI.relativize(URI.create(absolutePath)).toString();
    }

    /**
     * @return the absolute path for the given id
     */
    public static String getAbsoluteURL(RepositoryFileReference ref) {
        return Prefs.INSTANCE.getResourcePath() + "/"
                + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(ref));
    }

    public static URI getAbsoluteURI(GenericId id) {
        return Utils.createURI(Utils.getAbsoluteURL(id));
    }

    public static String doubleEscapeHTMLAndThenConvertNL2BR(String txt) {
        String res = Functions.escapeXml(txt);
        res = Functions.escapeXml(res);
        res = res.replaceAll("\\n", "<br/>");
        return res;
    }

    /**
     * This method is similar to {@link
     * Util#qname2href(java.lang.String, java.lang.Class, javax.xml.namespace.QName, java.lang.String)}, but treats winery's
     * internal ID model instead of the global TOSCA model
     *
     * @param id the id to create an <code>a href</code> element for
     * @return an <code>a</code> HTML element pointing to the given id
     */
    public static String getHREF(TOSCAComponentId id) {
        return "<a href=\"" + Utils.getAbsoluteURL(id) + "\">" + Functions.escapeXml(id.getXmlId().getDecoded())
                + "</a>";
    }

    public static String artifactTypeQName2href(QName qname) {
        return Util.qname2href(Prefs.INSTANCE.getResourcePath(), TArtifactType.class, qname);
    }

    public static String nodeTypeQName2href(QName qname) {
        return Util.qname2href(Prefs.INSTANCE.getResourcePath(), TNodeType.class, qname);
    }

    public static String relationshipTypeQName2href(QName qname) {
        return Util.qname2href(Prefs.INSTANCE.getResourcePath(), TRelationshipType.class, qname);
    }

    public static String policyTypeQName2href(QName qname) {
        return Util.qname2href(Prefs.INSTANCE.getResourcePath(), TPolicyType.class, qname);
    }

    /**
     * Returns the middle part of the package name or the JSP location
     *
     * @param type the type
     * @param separator the separator to be used, "." or "/"
     * @return string which can be used "in the middle" of a package or of a
     *         path to a JSP
     */
    public static String getIntermediateLocationStringForType(String type, String separator) {
        String location;
        if (type.contains("ServiceTemplate")) {
            location = "servicetemplates";
        } else {
            if (type.contains("TypeImplementation")) {
                location = "entitytypeimplementations";
            } else if (type.contains("Type")) {
                location = "entitytypes";
            } else if (type.contains("Import")) {
                location = "imports";
            } else {
                assert (type.contains("Template"));
                location = "entitytemplates";
            }
            // location now is the super pkg, we have to add a pkg of the type
            location = location + separator + type.toLowerCase() + "s";
        }
        return location;
    }

    /**
     * Required by topologyedit.jsp
     *
     * @return all known nodetype resources
     */
    public static Collection<NodeTypeResource> getAllNodeTypeResources() {
        @SuppressWarnings("unchecked")
        Collection<NodeTypeResource> res = (Collection<NodeTypeResource>) (Collection<?>) new NodeTypesResource()
                .getAll();
        return res;
    }

    /**
     * Required by topologyedit.jsp
     *
     * @return all known relation ship type resources
     */
    public static Collection<RelationshipTypeResource> getAllRelationshipTypeResources() {
        @SuppressWarnings("unchecked")
        Collection<RelationshipTypeResource> res = (Collection<RelationshipTypeResource>) (Collection<?>) new RelationshipTypesResource()
                .getAll();
        return res;
    }

    /**
     * @return the path to the Winery topology modeler. Required by
     *         functions.tld
     */
    public static String getWineryTopologyModelerPath() {
        return Prefs.INSTANCE.getWineryTopologyModelerPath();
    }

    /**
     * Detect the mime type of the stream. The stream is marked at the beginning
     * and reset at the end
     *
     * @param bis the stream
     * @param fn the fileName of the file belonging to the stream
     */
    public static String getMimeType(BufferedInputStream bis, String fn) throws IOException {
        AutoDetectParser parser = new AutoDetectParser();
        Detector detector = parser.getDetector();
        Metadata md = new Metadata();
        md.add(Metadata.RESOURCE_NAME_KEY, fn);
        org.apache.tika.mime.MediaType mediaType = detector.detect(bis, md);
        return mediaType.toString();
    }

    private static final MediaType MEDIATYPE_APPLICATION_OCTET_STREAM = MediaType
            .valueOf("application/octet-stream");

    /**
     * Fixes the mediaType if it is too vague (such as application/octet-stream)
     *
     * @return a more fitting MediaType or the original one if it is appropriate
     *         enough
     */
    public static MediaType getFixedMimeType(BufferedInputStream is, String fileName, MediaType mediaType) {
        if (mediaType.equals(Utils.MEDIATYPE_APPLICATION_OCTET_STREAM)) {
            // currently, we fix application/octet-stream only

            // TODO: instead of using apache tika, we could hve a user-configured map storing
            //  * media type
            //  * file extension

            try {
                return MediaType.valueOf(Utils.getMimeType(is, fileName));
            } catch (Exception e) {
                Utils.LOGGER.debug("Could not determine mimetype for " + fileName, e);
                // just keep the old one
                return mediaType;
            }
        } else {
            return mediaType;
        }
    }

    /**
     * Converts the given object to XML.
     *
     * Used in cases the given element is not annotated with @XmlRoot
     *
     * We cannot use {@literal Class<? extends TExtensibleElements>} as, for
     * instance, {@link TConstraint} does not inherit from
     * {@link TExtensibleElements}
     *
     * @param clazz the Class of the passed object, required if obj is null
     * @param obj the object to serialize
     */
    public static <T> Response getXML(Class<T> clazz, T obj) {
        // see commit ab4b5c547619c058990 for an implementation using getJAXBElement,
        // which can be directly passed as entity
        // the issue is that we want to have a *formatted* XML
        // Therefore, we serialize "by hand".
        String xml = Utils.getXMLAsString(clazz, obj, false);

        return Response.ok().type(MediaType.TEXT_XML).entity(xml).build();
    }

    public static <T> String getXMLAsString(Class<T> clazz, T obj, boolean includeProcessingInstruction) {
        JAXBElement<T> rootElement = Util.getJAXBElement(clazz, obj);
        Marshaller m = JAXBSupport.createMarshaller(includeProcessingInstruction);
        StringWriter w = new StringWriter();
        try {
            m.marshal(rootElement, w);
        } catch (JAXBException e) {
            Utils.LOGGER.error("Could not put content to string", e);
            throw new IllegalStateException(e);
        }
        return w.toString();
    }

    public static String getXMLAsString(Object obj) {
        if (obj instanceof Element) {
            // in case the object is a DOM element, we use the DOM functionality
            return Util.getXMLAsString((Element) obj);
        } else {
            return Utils.getXMLAsString(obj, false);
        }
    }

    public static <T> String getXMLAsString(T obj, boolean includeProcessingInstruction) {
        if (obj == null) {
            return "";
        }
        @SuppressWarnings("unchecked")
        Class<T> clazz = (Class<T>) obj.getClass();
        return Utils.getXMLAsString(clazz, obj, includeProcessingInstruction);
    }

    public static String getAllXSDElementDefinitionsForTypeAheadSelection() {
        Utils.LOGGER.entry();
        try {
            return Utils.getAllXSDefinitionsForTypeAheadSelection(XSConstants.ELEMENT_DECLARATION);
        } finally {
            Utils.LOGGER.exit();
        }
    }

    public static String getAllXSDTypeDefinitionsForTypeAheadSelection() {
        Utils.LOGGER.entry();
        try {
            return Utils.getAllXSDefinitionsForTypeAheadSelection(XSConstants.TYPE_DEFINITION);
        } finally {
            Utils.LOGGER.exit();
        }
    }

    public static String getAllXSDefinitionsForTypeAheadSelection(short type) {
        SortedSet<XSDImportId> allImports = Repository.INSTANCE.getAllTOSCAComponentIds(XSDImportId.class);

        Map<Namespace, Collection<String>> data = new HashMap<>();

        for (XSDImportId id : allImports) {
            XSDImportResource resource = new XSDImportResource(id);
            Collection<String> allLocalNames = resource.getAllDefinedLocalNames(type);

            Collection<String> list;
            if ((list = data.get(id.getNamespace())) == null) {
                // list does not yet exist
                list = new ArrayList<>();
                data.put(id.getNamespace(), list);
            }
            list.addAll(allLocalNames);
        }

        ArrayNode rootNode = Utils.mapper.createArrayNode();

        // ensure ordering in JSON object
        Collection<Namespace> allns = new TreeSet<>();
        allns.addAll(data.keySet());

        for (Namespace ns : allns) {
            Collection<String> localNames = data.get(ns);
            if (!localNames.isEmpty()) {
                ObjectNode groupEntry = Utils.mapper.createObjectNode();
                rootNode.add(groupEntry);
                groupEntry.put("text", ns.getDecoded());
                ArrayNode children = Utils.mapper.createArrayNode();
                groupEntry.put("children", children);
                Collection<String> sortedLocalNames = new TreeSet<>();
                sortedLocalNames.addAll(localNames);
                for (String localName : sortedLocalNames) {
                    String value = "{" + ns.getDecoded() + "}" + localName;
                    //noinspection UnnecessaryLocalVariable
                    String text = localName;
                    ObjectNode o = Utils.mapper.createObjectNode();
                    o.put("text", text);
                    o.put("value", value);
                    children.add(o);
                }
            }
        }

        try {
            return Utils.mapper.writeValueAsString(rootNode);
        } catch (JsonProcessingException e) {
            throw new IllegalStateException("Could not create JSON", e);
        }
    }

    public static Response getResponseForException(Exception e) {
        String msg;
        if (e.getCause() != null) {
            msg = e.getCause().getMessage();
        } else {
            msg = e.getMessage();
        }
        return Response.status(Status.INTERNAL_SERVER_ERROR).entity(msg).build();
    }

    /**
     * Returns the stored type for the given template
     *
     * Goes to the repository to retrieve stored data
     *
     * @param template the template to determine the type for
     */
    // we suppress "unchecked" as we use Class.forName
    @SuppressWarnings("unchecked")
    public static TEntityType getTypeForTemplate(TEntityTemplate template) {
        QName type = template.getType();

        // Possibilities:
        // a) try all possibly types whether an appropriate QName exists
        // b) derive type class from template class. Determine appropriate resource afterwards.
        // We go for b)

        String instanceResourceClassName = template.getClass().toString();
        int idx = instanceResourceClassName.lastIndexOf('.');
        // get everything from ".T", where "." is the last dot
        instanceResourceClassName = instanceResourceClassName.substring(idx + 2);
        // strip off "Template"
        instanceResourceClassName = instanceResourceClassName.substring(0,
                instanceResourceClassName.length() - "Template".length());
        // add "Type"
        instanceResourceClassName += "Type";

        // an id is required to instantiate the resource
        String idClassName = "org.eclipse.winery.common.ids.definitions." + instanceResourceClassName + "Id";

        String packageName = "org.eclipse.winery.repository.resources.entitytypes."
                + instanceResourceClassName.toLowerCase() + "s";
        // convert from NodeType to NodeTypesResource
        instanceResourceClassName += "Resource";
        instanceResourceClassName = packageName + "." + instanceResourceClassName;

        Utils.LOGGER.debug("idClassName: {}", idClassName);
        Utils.LOGGER.debug("className: {}", instanceResourceClassName);

        // Get instance of id class having "type" as id
        Class<? extends TOSCAComponentId> idClass;
        try {
            idClass = (Class<? extends TOSCAComponentId>) Class.forName(idClassName);
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException("Could not determine id class", e);
        }
        Constructor<? extends TOSCAComponentId> idConstructor;
        try {
            idConstructor = idClass.getConstructor(QName.class);
        } catch (NoSuchMethodException | SecurityException e) {
            throw new IllegalStateException("Could not get QName id constructor", e);
        }
        TOSCAComponentId typeId;
        try {
            typeId = idConstructor.newInstance(type);
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException e) {
            throw new IllegalStateException("Could not instantiate type", e);
        }

        // now instantiate the resource, where the type belongs to
        Class<? extends AbstractComponentInstanceResource> instanceResourceClass;
        try {
            instanceResourceClass = (Class<? extends AbstractComponentInstanceResource>) Class
                    .forName(instanceResourceClassName);
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException("Could not determine component instance resource class", e);
        }
        Constructor<? extends AbstractComponentInstanceResource> resConstructor;
        try {
            resConstructor = instanceResourceClass.getConstructor(typeId.getClass());
        } catch (NoSuchMethodException | SecurityException e) {
            throw new IllegalStateException("Could not get contructor", e);
        }
        AbstractComponentInstanceResource typeResource;
        try {
            typeResource = resConstructor.newInstance(typeId);
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException e) {
            throw new IllegalStateException("Could not instantiate resoruce", e);
        }

        // read the data from the resource and store it
        return (TEntityType) typeResource.getElement();
    }

    /**
     * referenced by functions.tld
     */
    public static Boolean isContainerLocallyAvailable() {
        return Prefs.INSTANCE.isContainerLocallyAvailable();
    }

    /**
     * referenced by functions.tld
     *
     * We need the bridge as functions (at tld) require a static method. We did
     * not want to put two methods in Prefs and therefore, we put the method
     * here.
     */
    public static Boolean isRestDocDocumentationAvailable() {
        return Prefs.INSTANCE.isRestDocDocumentationAvailable();
    }

    public static boolean isSuccessFulResponse(Response res) {
        return Status.fromStatusCode(res.getStatus()).getFamily().equals(Family.SUCCESSFUL);
    }

    /**
     * Converts the given String to an integer. Fallback if String is a float.
     * If String is an invalid number, "0" is returned
     */
    public static int convertStringToInt(String number) {
        int intTop = 0;
        try {
            intTop = Integer.parseInt(number);
        } catch (NumberFormatException e) {
            try {
                float floatTop = Float.parseFloat(number);
                intTop = Math.round(floatTop);
            } catch (NumberFormatException e2) {
                // do nothing
            }
        }

        return intTop;
    }

    /**
     * Checks whether a given resource (with absolute URL!) is available with a
     * HEAD request on it.
     */
    public static boolean isResourceAvailable(String path) {
        Client client = Client.create();
        WebResource wr = client.resource(path);
        boolean res;
        try {
            ClientResponse response = wr.head();
            res = (response.getStatusInfo().getFamily().equals(Family.SUCCESSFUL));
        } catch (com.sun.jersey.api.client.ClientHandlerException ex) {
            // In the case of a java.net.ConnectException, return false
            res = false;
        }
        return res;
    }

    public static Set<String> clean(Set<String> set) {
        Set<String> newSet = new HashSet<String>();

        for (String setItem : set) {
            if (setItem != null && !setItem.trim().isEmpty() && !setItem.equals("null")) {
                newSet.add(setItem);
            }
        }

        return newSet;
    }

    public static Set<QName> cleanQNameSet(Set<QName> set) {
        Set<QName> newSet = new HashSet<QName>();

        for (QName setItem : set) {
            if (setItem != null && !setItem.getLocalPart().equals("null")) {
                newSet.add(setItem);
            }
        }
        return newSet;
    }

    public static ServiceTemplateId cloneServiceTemplate(ServiceTemplateId serviceTemplate, String newName,
            String artifactName) throws JAXBException, IllegalArgumentException, IOException {

        ServiceTemplateId newServiceTemplateId = new ServiceTemplateId(serviceTemplate.getNamespace().getDecoded(),
                newName, false);

        RepositoryFileReference fileRef = new RepositoryFileReference(newServiceTemplateId,
                "ServiceTemplate.tosca");

        Definitions defs = new ServiceTemplateResource(serviceTemplate).getDefinitions();

        defs.setId(newName + "Definitions");
        defs.setName(newName + "Definitions generated from Artifact " + artifactName);

        TServiceTemplate oldSTModel = null;

        for (TExtensibleElements el : defs.getServiceTemplateOrNodeTypeOrNodeTypeImplementation()) {
            if (el instanceof TServiceTemplate) {
                oldSTModel = (TServiceTemplate) el;
            }
        }

        oldSTModel.setId(newName);
        oldSTModel.setName(newName + " generated from Artifact " + artifactName);

        // remove xaaspackager tags
        Collection<TTag> toRemove = new ArrayList<TTag>();

        for (TTag tag : oldSTModel.getTags().getTag()) {
            switch (tag.getName()) {
            case "xaasPackageNode":
            case "xaasPackageArtifactType":
            case "xaasPackageDeploymentArtifact":
                toRemove.add(tag);
                break;
            default:
                break;
            }
        }

        oldSTModel.getTags().getTag().removeAll(toRemove);

        JAXBContext context = JAXBContext.newInstance(Definitions.class);
        Marshaller m = context.createMarshaller();
        StringWriter sw = new StringWriter();
        m.marshal(defs, sw);

        String xmlString = sw.toString();

        Repository.INSTANCE.putContentToFile(fileRef, xmlString,
                MediaType.valueOf(MimeTypes.MIMETYPE_TOSCA_DEFINITIONS));

        return newServiceTemplateId;
    }

    public static boolean containsNodeType(TServiceTemplate serviceTemplate, QName nodeType) {
        List<TEntityTemplate> templates = serviceTemplate.getTopologyTemplate()
                .getNodeTemplateOrRelationshipTemplate();

        return templates.stream().filter(template -> template instanceof TNodeTemplate)
                .anyMatch(template -> template.getType().equals(nodeType));
    }

    public static boolean containsNodeTypes(TServiceTemplate serviceTemplate, Collection<QName> nodeTypes) {
        return nodeTypes.stream().allMatch(nodeType -> Utils.containsNodeType(serviceTemplate, nodeType));
    }

    public static boolean containsTag(TServiceTemplate serviceTemplate, String tagKey) {
        return Utils.getTagValue(serviceTemplate, tagKey) != null;
    }

    public static boolean containsTag(TServiceTemplate serviceTemplate, String tagKey, String tagValue) {
        String value = Utils.getTagValue(serviceTemplate, tagKey);
        return value != null && value.equals(tagValue);
    }

    public static boolean containsTags(TServiceTemplate serviceTemplate, Collection<String> tags) {
        for (String tag : tags) {
            if (tag.contains(":")) {
                String key = tag.split(":")[0];
                String value = tag.split(":")[1];
                if (!Utils.containsTag(serviceTemplate, key, value)) {
                    return false;
                }
            } else {
                if (!Utils.containsTag(serviceTemplate, tag)) {
                    return false;
                }
            }
        }

        return true;
    }

    public static ArtifactTemplateId createArtifactTemplate(InputStream uploadedInputStream,
            FormDataContentDisposition fileDetail, FormDataBodyPart body, QName artifactType, UriInfo uriInfo) {

        ArtifactTemplatesResource templateResource = new ArtifactTemplatesResource();
        templateResource.onPost("http://opentosca.org/xaaspackager", "xaasPackager_" + fileDetail.getFileName(),
                artifactType.toString());

        ArtifactTemplateId artifactTemplateId = new ArtifactTemplateId("http://opentosca.org/xaaspackager",
                "xaasPackager_" + fileDetail.getFileName(), false);

        ArtifactTemplateResource atRes = new ArtifactTemplateResource(artifactTemplateId);
        atRes.getFilesResource().onPost(uploadedInputStream, fileDetail, body, uriInfo);

        return artifactTemplateId;
    }

    public static String getTagValue(TServiceTemplate serviceTemplate, String tagKey) {
        if (serviceTemplate.getTags() != null) {
            for (TTag tag : serviceTemplate.getTags().getTag()) {
                if (tag.getName().equals(tagKey)) {
                    return tag.getValue();
                }
            }
        }
        return null;
    }

    public static boolean hasDA(ServiceTemplateId serviceTemplate, String nodeTemplateId,
            String deploymentArtifactId) {
        ServiceTemplateResource stRes = new ServiceTemplateResource(serviceTemplate);
        try {
            stRes.getTopologyTemplateResource().getNodeTemplatesResource().getEntityResource(nodeTemplateId)
                    .getDeploymentArtifacts().getEntityResource(deploymentArtifactId);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    public static boolean injectArtifactTemplateIntoDeploymentArtifact(ServiceTemplateId serviceTemplate,
            String nodeTemplateId, String deploymentArtifactId, ArtifactTemplateId artifactTemplate) {

        ServiceTemplateResource stRes = new ServiceTemplateResource(serviceTemplate);
        stRes.getTopologyTemplateResource().getNodeTemplatesResource().getEntityResource(nodeTemplateId)
                .getDeploymentArtifacts().getEntityResource(deploymentArtifactId)
                .setArtifactTemplate(artifactTemplate);

        return true;
    }
}