Java tutorial
/******************************************************************************* * Copyright (c) 2012-2017 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 * Nicole Keppler, Lukas Balzer - changes for angular frontend * Armin Hneburg - add initial git support * Philipp Meyer - support for source directory *******************************************************************************/ package org.eclipse.winery.repository.rest; 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.nio.file.attribute.FileTime; import java.security.AccessControlException; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.HttpHeaders; 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.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.elements.TOSCAElementId; import org.eclipse.winery.model.selfservice.Application; import org.eclipse.winery.model.tosca.Definitions; import org.eclipse.winery.model.tosca.HasType; 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.model.tosca.utils.ModelUtilities; import org.eclipse.winery.repository.Constants; import org.eclipse.winery.repository.backend.BackendUtils; import org.eclipse.winery.repository.backend.RepositoryFactory; import org.eclipse.winery.repository.backend.constants.MediaTypes; import org.eclipse.winery.repository.backend.xsd.NamespaceAndDefinedLocalNames; import org.eclipse.winery.repository.configuration.Environment; import org.eclipse.winery.repository.export.CSARExporter; import org.eclipse.winery.repository.export.TOSCAExportUtil; import org.eclipse.winery.repository.rest.datatypes.NamespaceAndDefinedLocalNamesForAngular; import org.eclipse.winery.repository.rest.resources.AbstractComponentInstanceResource; import org.eclipse.winery.repository.rest.resources.AbstractComponentsResource; import org.eclipse.winery.repository.rest.resources._support.IPersistable; import org.eclipse.winery.repository.rest.resources._support.ResourceCreationResult; import org.eclipse.winery.repository.rest.resources.apiData.QNameWithTypeApiData; import org.eclipse.winery.repository.rest.resources.entitytemplates.artifacttemplates.ArtifactTemplateResource; import org.eclipse.winery.repository.rest.resources.entitytemplates.artifacttemplates.ArtifactTemplatesResource; import org.eclipse.winery.repository.rest.resources.entitytypes.TopologyGraphElementEntityTypeResource; import org.eclipse.winery.repository.rest.resources.entitytypes.nodetypes.NodeTypeResource; import org.eclipse.winery.repository.rest.resources.entitytypes.nodetypes.NodeTypesResource; import org.eclipse.winery.repository.rest.resources.entitytypes.relationshiptypes.RelationshipTypeResource; import org.eclipse.winery.repository.rest.resources.entitytypes.relationshiptypes.RelationshipTypesResource; import org.eclipse.winery.repository.rest.resources.servicetemplates.ServiceTemplateResource; 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.ContentDisposition; import com.sun.jersey.core.header.FormDataContentDisposition; import com.sun.jersey.multipart.FormDataBodyPart; import org.apache.commons.configuration.Configuration; import org.apache.commons.lang3.StringUtils; import org.apache.taglibs.standard.functions.Functions; import org.slf4j.ext.XLogger; import org.slf4j.ext.XLoggerFactory; /** * 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 RestUtils { private static final XLogger LOGGER = XLoggerFactory.getXLogger(RestUtils.class); // 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 = "[" + RestUtils.RANGE_NCNAMESTARTCHAR + "]"; private static final String RANGE_NCNAMECHAR = RestUtils.RANGE_NCNAMESTARTCHAR + "\\-\\.0-9\\u00b7\\u0300-\\u036f\\u203f-\\u2040"; private static final String REGEX_INVALIDNCNAMESCHAR = "[^" + RestUtils.RANGE_NCNAMECHAR + "]"; static { if (Locale.getDefault() != Locale.ENGLISH) { try { // needed for {@link // returnRepoPath(File, String)} Locale.setDefault(Locale.ENGLISH); } catch (AccessControlException e) { // Happens at Google App Engine LOGGER.error("Could not switch locale to English", e); } } } 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(); } } /** * 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(RestUtils.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(RestUtils.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(RestUtils.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 (Exception 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(); } /** * Zipps the folder reference given by the id. As filename the parent id is used. */ public static Response getZippedContents(final GenericId id) { StreamingOutput so = output -> { try { RepositoryFactory.getRepository().getZippedContents(id, output); } catch (Exception e) { throw new WebApplicationException(e); } }; StringBuilder sb = new StringBuilder(); sb.append("attachment;filename=\""); sb.append(id.getParent().getXmlId().getEncoded()); sb.append(Constants.SUFFIX_ZIP); 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 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()); } /** * 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 = RestUtils.getTypeForComponentContainer(containerClass) + "Id"; return Util.getComponentIdClass(idClassName); } /** * @return the absolute path for the given id */ public static String getAbsoluteURL(GenericId id) { return Environment.getUrlConfiguration().getRepositoryApiUrl() + "/" + Util.getUrlPath(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 = Environment.getUrlConfiguration().getRepositoryApiUrl() + "/" + Util.getUrlPath(id); return baseURI.relativize(URI.create(absolutePath)).toString(); } /** * @return the absolute path for the given id */ public static String getAbsoluteURL(RepositoryFileReference ref) { return Environment.getUrlConfiguration().getRepositoryApiUrl() + "/" + Util.getUrlPath(ref); } public static URI getAbsoluteURI(GenericId id) { return RestUtils.createURI(RestUtils.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=\"" + Environment.getUrlConfiguration().getRepositoryUiUrl() + "/" + Util.getUrlPath(id) + "\">" + Functions.escapeXml(id.getXmlId().getDecoded()) + "</a>"; } public static String artifactTypeQName2href(QName qname) { return Util.qname2href(Environment.getUrlConfiguration().getRepositoryUiUrl(), TArtifactType.class, qname); } public static String nodeTypeQName2href(QName qname) { return Util.qname2href(Environment.getUrlConfiguration().getRepositoryUiUrl(), TNodeType.class, qname); } public static String relationshipTypeQName2href(QName qname) { return Util.qname2href(Environment.getUrlConfiguration().getRepositoryUiUrl(), TRelationshipType.class, qname); } public static String policyTypeQName2href(QName qname) { return Util.qname2href(Environment.getUrlConfiguration().getRepositoryUiUrl(), 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; } /** * 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 = BackendUtils.getXMLAsString(clazz, obj, false); return Response.ok().type(MediaType.TEXT_XML).entity(xml).build(); } 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.rest.resources.entitytypes." + instanceResourceClassName.toLowerCase() + "s"; // convert from NodeType to NodeTypesResource instanceResourceClassName += "Resource"; instanceResourceClassName = packageName + "." + instanceResourceClassName; RestUtils.LOGGER.debug("idClassName: {}", idClassName); RestUtils.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(); } 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(); RepositoryFactory.getRepository().putContentToFile(fileRef, xmlString, MediaTypes.MEDIATYPE_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 -> RestUtils.containsNodeType(serviceTemplate, nodeType)); } public static boolean containsTag(TServiceTemplate serviceTemplate, String tagKey) { return RestUtils.getTagValue(serviceTemplate, tagKey) != null; } public static boolean containsTag(TServiceTemplate serviceTemplate, String tagKey, String tagValue) { String value = RestUtils.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 (!RestUtils.containsTag(serviceTemplate, key, value)) { return false; } } else { if (!RestUtils.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(); QNameWithTypeApiData qNameApiData = new QNameWithTypeApiData(); qNameApiData.localname = "xaasPackager_" + fileDetail.getFileName(); qNameApiData.namespace = "http://opentosca.org/xaaspackager"; qNameApiData.type = artifactType.toString(); templateResource.onJsonPost(qNameApiData); 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; } /** * Persists the resource and returns appropriate response */ public static Response persist(IPersistable res) { return persistWithResponseBuilder(res).build(); } /** * Persists the given object */ public static Response persist(Application application, RepositoryFileReference data_xml_ref, String mimeType) { Response r; try { BackendUtils.persist(application, data_xml_ref, org.apache.tika.mime.MediaType.parse(mimeType)); } catch (IOException e) { LOGGER.debug("Could not persist resource", e); throw new WebApplicationException(e); } return Response.noContent().build(); } public static Response.ResponseBuilder persistWithResponseBuilder(IPersistable res) { Response r; try { BackendUtils.persist(res.getDefinitions(), res.getRepositoryFileReference(), MediaTypes.MEDIATYPE_TOSCA_DEFINITIONS); } catch (IOException e) { LOGGER.debug("Could not persist resource", e); throw new WebApplicationException(e); } return Response.noContent(); } public static Response rename(TOSCAComponentId oldId, TOSCAComponentId newId) { try { RepositoryFactory.getRepository().rename(oldId, newId); } catch (IOException e) { LOGGER.error(e.getMessage(), e); return Response.serverError().entity(e.getMessage()).build(); } URI uri = RestUtils.getAbsoluteURI(newId); return Response.created(uri).entity(uri.toString()).build(); } /** * Deletes the whole namespace in the component */ public static Response delete(Class<? extends TOSCAComponentId> toscaComponentIdClazz, String namespaceStr) { Namespace namespace = new Namespace(namespaceStr, true); try { RepositoryFactory.getRepository().forceDelete(toscaComponentIdClazz, namespace); } catch (IOException e) { LOGGER.error(e.getMessage(), e); return Response.serverError().entity(e.getMessage()).build(); } return Response.noContent().build(); } /** * Deletes given file/dir and returns appropriate response code */ public static Response delete(GenericId id) { if (!RepositoryFactory.getRepository().exists(id)) { return Response.status(Status.NOT_FOUND).build(); } try { RepositoryFactory.getRepository().forceDelete(id); } catch (IOException e) { LOGGER.error(e.getMessage(), e); return Response.serverError().entity(e.getMessage()).build(); } return Response.noContent().build(); } /** * Deletes given file and returns appropriate response code */ public static Response delete(RepositoryFileReference ref) { if (!RepositoryFactory.getRepository().exists(ref)) { return Response.status(Status.NOT_FOUND).build(); } try { RepositoryFactory.getRepository().forceDelete(ref); } catch (IOException e) { LOGGER.error(e.getMessage(), e); return Response.serverError().entity(e.getMessage()).build(); } return Response.noContent().build(); } /** * Generates given TOSCA element and returns appropriate response code <br /> * * In the case of an existing resource, the other possible return code is 302. This code has no Status constant, * therefore we use Status.CONFLICT, which is also possible. * * @return <ul> <li> <ul> <li>Status.CREATED (201) if the resource has been created,</li> <li>Status.CONFLICT if the * resource already exists,</li> <li>Status.INTERNAL_SERVER_ERROR (500) if something went wrong</li> </ul> </li> * <li>URI: the absolute URI of the newly created resource</li> </ul> */ public static ResourceCreationResult create(GenericId id) { ResourceCreationResult res = new ResourceCreationResult(); if (RepositoryFactory.getRepository().exists(id)) { // res.setStatus(302); res.setStatus(Status.CONFLICT); } else { if (RepositoryFactory.getRepository().flagAsExisting(id)) { res.setStatus(Status.CREATED); // @formatter:off // This method is a generic method // We cannot return an "absolute" URL as the URL is always // relative to the caller // Does not work: String path = Environment.getUrlConfiguration().getRepositoryApiUrl() // + "/" + // Utils.getUrlPathForPathInsideRepo(id.getPathInsideRepo()); // We distinguish between two cases: TOSCAcomponentId and // TOSCAelementId // @formatter:on String path; if (id instanceof TOSCAComponentId) { // here, we return namespace + id, as it is only possible to // post on the TOSCA component*s* resource to create an // instance of a TOSCA component TOSCAComponentId tcId = (TOSCAComponentId) id; path = tcId.getNamespace().getEncoded() + "/" + tcId.getXmlId().getEncoded() + "/"; } else { assert (id instanceof TOSCAElementId); // We just return the id as we assume that only the parent // of this id may create sub elements path = id.getXmlId().getEncoded() + "/"; } // we have to encode it twice to get correct URIs path = Util.getUrlPath(path); URI uri = RestUtils.createURI(path); res.setUri(uri); res.setId(id); } else { res.setStatus(Status.INTERNAL_SERVER_ERROR); } } return res; } /** * Sends the file if modified and "not modified" if not modified future work may put each file with a unique id in a * separate folder in tomcat * use that static URL for each file * if file is modified, URL of file changes * -> * client always fetches correct file * * additionally "Vary: Accept" header is added (enables caching of the response) * * method header for calling method public <br /> <code>Response getXY(@HeaderParam("If-Modified-Since") String * modified) {...}</code> * * @param ref references the file to be send * @param modified - HeaderField "If-Modified-Since" - may be "null" * @return Response to be sent to the client */ public static Response returnRepoPath(RepositoryFileReference ref, String modified) { return RestUtils.returnRefAsResponseBuilder(ref, modified).build(); } /** * This is not repository specific, but we leave it close to the only caller * * If the passed ref is newer than the modified date (or the modified date is null), an OK response with an * inputstream pointing to the path is returned */ private static Response.ResponseBuilder returnRefAsResponseBuilder(RepositoryFileReference ref, String modified) { if (!RepositoryFactory.getRepository().exists(ref)) { return Response.status(Status.NOT_FOUND); } FileTime lastModified; try { lastModified = RepositoryFactory.getRepository().getLastModifiedTime(ref); } catch (IOException e1) { LOGGER.debug("Could not get lastModifiedTime", e1); return Response.serverError(); } // do we really need to send the file or can send "not modified"? if (!BackendUtils.isFileNewerThanModifiedDate(lastModified.toMillis(), modified)) { return Response.status(Status.NOT_MODIFIED); } Response.ResponseBuilder res; try { res = Response.ok(RepositoryFactory.getRepository().newInputStream(ref)); } catch (IOException e) { LOGGER.debug("Could not open input stream", e); return Response.serverError(); } res = res.lastModified(new Date(lastModified.toMillis())); // vary:accept header is always set to be safe res = res.header(HttpHeaders.VARY, HttpHeaders.ACCEPT); // determine and set MIME content type try { res = res.header(HttpHeaders.CONTENT_TYPE, RepositoryFactory.getRepository().getMimeType(ref)); } catch (IOException e) { LOGGER.debug("Could not determine mime type", e); return Response.serverError(); } // set filename ContentDisposition contentDisposition = ContentDisposition.type("attachment").fileName(ref.getFileName()) .modificationDate(new Date(lastModified.toMillis())).build(); res.header("Content-Disposition", contentDisposition); return res; } /** * Updates the given property in the given configuration. Currently always returns "no content", because the * underlying class does not report any errors during updating. <br /> * * If null or "" is passed as value, the property is cleared * * @return Status.NO_CONTENT */ public static Response updateProperty(Configuration configuration, String property, String val) { if (StringUtils.isBlank(val)) { configuration.clearProperty(property); } else { configuration.setProperty(property, val); } return Response.noContent().build(); } /** * Writes data to file. Replaces the file's content with the given content. The file does not need to exist * * @param ref Reference to the File to write to (overwrite) * @param content the data to write * @return a JAX-RS Response containing the result. NOCONTENT if successful, InternalSeverError otherwise */ public static Response putContentToFile(RepositoryFileReference ref, String content, @SuppressWarnings("SameParameterValue") org.apache.tika.mime.MediaType mediaType) { try { RepositoryFactory.getRepository().putContentToFile(ref, content, mediaType); } catch (IOException e) { LOGGER.error(e.getMessage(), e); return Response.serverError().entity(e.getMessage()).build(); } return Response.noContent().build(); } public static Response putContentToFile(RepositoryFileReference ref, String content, @SuppressWarnings("SameParameterValue") MediaType mediaType) { return putContentToFile(ref, content, org.apache.tika.mime.MediaType.parse(mediaType.toString())); } public static Response putContentToFile(RepositoryFileReference ref, InputStream inputStream, org.apache.tika.mime.MediaType mediaType) { try { RepositoryFactory.getRepository().putContentToFile(ref, inputStream, mediaType); } catch (IOException e) { LOGGER.error(e.getMessage(), e); return Response.serverError().entity(e.getMessage()).build(); } return Response.noContent().build(); } public static Response putContentToFile(RepositoryFileReference ref, InputStream inputStream, MediaType mediaType) { return putContentToFile(ref, inputStream, org.apache.tika.mime.MediaType.parse(mediaType.toString())); } /** * Updates the color if the color is not yet existent * * @param name the name of the component. Used as basis for a generated color * @param qname the QName of the color attribute * @param otherAttributes the plain "XML" attributes. They are used to check */ public static String getColorAndSetDefaultIfNotExisting(String name, QName qname, Map<QName, String> otherAttributes, TopologyGraphElementEntityTypeResource res) { String colorStr = otherAttributes.get(qname); if (colorStr == null) { colorStr = ModelUtilities.getColor(name); otherAttributes.put(qname, colorStr); RestUtils.persist(res); } return colorStr; } /** * This is a quick helper method. The code should be refactored to use HasType on the element directly instead of * going through the resource. The method was implemented, because it is not that easy to get the id of the element * belonging to a resource. * * @param res a resource, where the associated element has a type. Example: EntityTypeImplementationResource * @return the QName of the associated type */ public static QName getType(IPersistable res) { TOSCAComponentId id = (TOSCAComponentId) res.getRepositoryFileReference().getParent(); final HasType element = (HasType) RepositoryFactory.getRepository().getDefinitions(id).getElement(); return element.getTypeAsQName(); } public static List<NamespaceAndDefinedLocalNamesForAngular> convert(List<NamespaceAndDefinedLocalNames> list) { return list.stream() .map(namespaceAndDefinedLocalNames -> new NamespaceAndDefinedLocalNamesForAngular( namespaceAndDefinedLocalNames.getNamespace(), namespaceAndDefinedLocalNames.getDefinedLocalNames())) .collect(Collectors.toList()); } }