Add winery source code
[vfc/nfvo/wfengine.git] / winery / org.eclipse.winery.repository / src / main / java / org / eclipse / winery / repository / resources / artifacts / GenericArtifactsResource.java
1 /*******************************************************************************
2  * Copyright (c) 2012-2013 University of Stuttgart.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * and the Apache License 2.0 which both accompany this distribution,
6  * and are available at http://www.eclipse.org/legal/epl-v10.html
7  * and http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Contributors:
10  *     Oliver Kopp - initial API and implementation
11  *******************************************************************************/
12 package org.eclipse.winery.repository.resources.artifacts;
13
14 import java.io.BufferedInputStream;
15 import java.io.File;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.io.StringReader;
19 import java.net.MalformedURLException;
20 import java.net.URI;
21 import java.net.URL;
22 import java.nio.file.Files;
23 import java.nio.file.Path;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.SortedSet;
29
30 import javax.ws.rs.Consumes;
31 import javax.ws.rs.FormParam;
32 import javax.ws.rs.POST;
33 import javax.ws.rs.Produces;
34 import javax.ws.rs.core.Context;
35 import javax.ws.rs.core.MediaType;
36 import javax.ws.rs.core.Response;
37 import javax.ws.rs.core.Response.Status;
38 import javax.ws.rs.core.UriInfo;
39 import javax.xml.namespace.QName;
40 import javax.xml.parsers.DocumentBuilder;
41 import javax.xml.parsers.DocumentBuilderFactory;
42 import javax.xml.parsers.ParserConfigurationException;
43
44 import org.apache.commons.lang3.StringUtils;
45 import org.eclipse.winery.common.RepositoryFileReference;
46 import org.eclipse.winery.common.Util;
47 import org.eclipse.winery.common.ids.Namespace;
48 import org.eclipse.winery.common.ids.XMLId;
49 import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId;
50 import org.eclipse.winery.common.ids.definitions.ArtifactTypeId;
51 import org.eclipse.winery.common.ids.definitions.NodeTypeId;
52 import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
53 import org.eclipse.winery.generators.ia.Generator;
54 import org.eclipse.winery.model.tosca.TDeploymentArtifact;
55 import org.eclipse.winery.model.tosca.TEntityTemplate.Properties;
56 import org.eclipse.winery.model.tosca.TImplementationArtifacts.ImplementationArtifact;
57 import org.eclipse.winery.model.tosca.TInterface;
58 import org.eclipse.winery.model.tosca.TNodeType;
59 import org.eclipse.winery.repository.Utils;
60 import org.eclipse.winery.repository.backend.BackendUtils;
61 import org.eclipse.winery.repository.backend.Repository;
62 import org.eclipse.winery.repository.backend.ResourceCreationResult;
63 import org.eclipse.winery.repository.backend.filebased.FileUtils;
64 import org.eclipse.winery.repository.datatypes.ids.elements.ArtifactTemplateDirectoryId;
65 import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource;
66 import org.eclipse.winery.repository.resources.AbstractComponentsResource;
67 import org.eclipse.winery.repository.resources.IHasTypeReference;
68 import org.eclipse.winery.repository.resources.INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource;
69 import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource;
70 import org.eclipse.winery.repository.resources.entitytemplates.PropertiesResource;
71 import org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates.ArtifactTemplateResource;
72 import org.eclipse.winery.repository.resources.entitytypeimplementations.EntityTypeImplementationResource;
73 import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationResource;
74 import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationResource;
75 import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource;
76 import org.eclipse.winery.repository.resources.servicetemplates.topologytemplates.NodeTemplateResource;
77 import org.restdoc.annotations.RestDoc;
78 import org.restdoc.annotations.RestDocParam;
79 import org.slf4j.Logger;
80 import org.slf4j.LoggerFactory;
81 import org.w3c.dom.Document;
82 import org.w3c.dom.Element;
83 import org.w3c.dom.Text;
84 import org.xml.sax.InputSource;
85
86 import com.sun.jersey.api.view.Viewable;
87
88 /**
89  * Resource handling both deployment and implementation artifacts
90  * 
91  */
92 public abstract class GenericArtifactsResource<ArtifactResource extends GenericArtifactResource<ArtifactT>, ArtifactT> extends EntityWithIdCollectionResource<ArtifactResource, ArtifactT> {
93         
94         private static final Logger logger = LoggerFactory.getLogger(GenericArtifactsResource.class);
95         
96         protected final INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource resWithNamespace;
97         
98         
99         public GenericArtifactsResource(Class<ArtifactResource> entityResourceTClazz, Class<ArtifactT> entityTClazz, List<ArtifactT> list, INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource res) {
100                 super(entityResourceTClazz, entityTClazz, list, GenericArtifactsResource.getAbstractComponentInstanceResource(res));
101                 this.resWithNamespace = res;
102         }
103         
104         // @formatter:off
105
106         /**
107          * @return TImplementationArtifact | TDeploymentArtifact (XML) | URL of generated IA zip (in case of autoGenerateIA)
108          */
109         @POST
110         @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
111         @Produces(MediaType.TEXT_XML)
112         @RestDoc(methodDescription = "Creates a new implementation/deployment artifact. " +
113                         "If an implementation artifact with the same name already exists, it is <em>overridden</em>.")
114         @SuppressWarnings("unchecked")
115         public Response onPost(
116                         @FormParam("artifactName")
117                         @RestDocParam(description = "This is the name of the implementation/deployment artifact. " +
118                                         "Is <em>also</em>used as prefix of the name of the corresponding artifact template if no specific template is provided. " +
119                                         "In contrast to CS01, we require a artifactName also for the implementationArtifact to be able to properly referencing it.")
120                         String artifactNameStr,
121
122                         @FormParam("artifactTemplate")
123                         @RestDocParam(description = "QName of the artifact Template - used by Winery Backend instead of artifactTemplateName + artifactTemplateNS")
124                         String artifactTemplate,
125
126                         @FormParam("artifactTemplateName")
127                         @RestDocParam(description = "if provided and autoCreateArtifactTemplate, a template of this id localname and artifactTemplateNS generated. " +
128                         "Winery always sends this string if auto creation is desired.")
129                         String artifactTemplateName,
130
131                         @FormParam("artifactTemplateNS")
132                         String artifactTemplateNS,
133
134                         @FormParam("autoCreateArtifactTemplate")
135                         @RestDocParam(description = "if empty, no, or false, no artifact template is created. " +
136                         "An artifact type has to be given in that case. " +
137                         "Furthermore, an artifact template name + artifact template namespace has to be provided. " +
138                         "Otherwise, the artifactNameStr is used as name for the artifact and a <em>new</em> artifact template is created having {@code <artifactNameString>Template} as name")
139                         String autoCreateArtifactTemplate,
140
141                         @FormParam("artifactType")
142                         @RestDocParam(description = "QName of the type, format: {namespace}localname. " +
143                                         "Optional if artifactTemplateName + artifactTempalteNS is provided")
144                         String artifactTypeStr,
145
146                         @FormParam("artifactSpecificContent")
147                         @RestDocParam(description = "<em>XML</em> snippet that should be put inside the artifact XML in the TOSCA serialization. " +
148                                         "This feature will be removed soon. " +
149                                         "TODO: This only works if there is a single child element expected and not several elements. " +
150                                         "Future versions of the Winery will support arbitrary content there.")
151                         String artifactSpecificContent,
152
153                         @FormParam("interfaceName")
154                         String interfaceNameStr,
155
156                         @FormParam("operationName")
157                         String operationNameStr,
158
159                         @FormParam("autoGenerateIA")
160                         @RestDocParam(description = "If not empty, the IA generator will be called")
161                         String autoGenerateIA,
162
163                         @FormParam("javapackage")
164                         @RestDocParam(description = "The Java package to use for IA generation")
165                         String javapackage,
166
167                         @Context UriInfo uriInfo
168         ){
169                 // we assume that the parent ComponentInstance container exists
170
171                 // @formatter:on
172                 
173                 if (StringUtils.isEmpty(artifactNameStr)) {
174                         return Response.status(Status.BAD_REQUEST).entity("Empty artifactName").build();
175                 }
176                 if (StringUtils.isEmpty(artifactTypeStr)) {
177                         if (StringUtils.isEmpty(artifactTemplateName) || StringUtils.isEmpty(artifactTemplateNS)) {
178                                 if (StringUtils.isEmpty(artifactTemplate)) {
179                                         return Response.status(Status.BAD_REQUEST).entity("No artifact type given and no template given. Cannot guess artifact type").build();
180                                 }
181                         }
182                 }
183                 
184                 if (!StringUtils.isEmpty(autoGenerateIA)) {
185                         if (StringUtils.isEmpty(javapackage)) {
186                                 return Response.status(Status.BAD_REQUEST).entity("no java package name supplied for IA auto generation.").build();
187                         }
188                         if (StringUtils.isEmpty(interfaceNameStr)) {
189                                 return Response.status(Status.BAD_REQUEST).entity("no interface name supplied for IA auto generation.").build();
190                         }
191                 }
192                 
193                 // convert second calling form to first calling form
194                 if (!StringUtils.isEmpty(artifactTemplate)) {
195                         QName qname = QName.valueOf(artifactTemplate);
196                         artifactTemplateName = qname.getLocalPart();
197                         artifactTemplateNS = qname.getNamespaceURI();
198                 }
199                 
200                 Document doc = null;
201                 
202                 // check artifact specific content for validity
203                 // if invalid, abort and do not create anything
204                 if (!StringUtils.isEmpty(artifactSpecificContent)) {
205                         try {
206                                 DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
207                                 InputSource is = new InputSource();
208                                 StringReader sr = new StringReader(artifactSpecificContent);
209                                 is.setCharacterStream(sr);
210                                 doc = db.parse(is);
211                         } catch (Exception e) {
212                                 // FIXME: currently we allow a single element only. However, the content should be internally wrapped by an (arbitrary) XML element as the content will be nested in the artifact element, too
213                                 GenericArtifactsResource.logger.debug("Invalid content", e);
214                                 return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
215                         }
216                 }
217                 
218                 // determine artifactTemplate and artifactType
219                 
220                 ArtifactTypeId artifactTypeId;
221                 ArtifactTemplateId artifactTemplateId = null;
222                 ArtifactTemplateResource artifactTemplateResource = null;
223                 
224                 boolean doAutoCreateArtifactTemplate = !(StringUtils.isEmpty(autoCreateArtifactTemplate) || autoCreateArtifactTemplate.equalsIgnoreCase("no") || autoCreateArtifactTemplate.equalsIgnoreCase("false"));
225                 if (!doAutoCreateArtifactTemplate) {
226                         // no auto creation
227                         if (!StringUtils.isEmpty(artifactTemplateName) && !StringUtils.isEmpty(artifactTemplateNS)) {
228                                 QName artifactTemplateQName = new QName(artifactTemplateNS, artifactTemplateName);
229                                 artifactTemplateId = BackendUtils.getTOSCAcomponentId(ArtifactTemplateId.class, artifactTemplateQName);
230                         }
231                         if (StringUtils.isEmpty(artifactTypeStr)) {
232                                 // derive the type from the artifact template
233                                 if (artifactTemplateId == null) {
234                                         return Response.status(Status.NOT_ACCEPTABLE).entity("No artifactTemplate and no artifactType provided. Deriving the artifactType is not possible.").build();
235                                 }
236                                 artifactTemplateResource = new ArtifactTemplateResource(artifactTemplateId);
237                                 artifactTypeId = BackendUtils.getTOSCAcomponentId(ArtifactTypeId.class, artifactTemplateResource.getType());
238                         } else {
239                                 // artifactTypeStr is directly given, use that
240                                 artifactTypeId = BackendUtils.getTOSCAcomponentId(ArtifactTypeId.class, artifactTypeStr);
241                         }
242                 } else {
243                         // do the artifact template auto creation magic
244                         
245                         if (StringUtils.isEmpty(artifactTypeStr)) {
246                                 return Response.status(Status.BAD_REQUEST).entity("Artifact template auto creation requested, but no artifact type supplied.").build();
247                         }
248                         
249                         // we assume that the type points to a valid artifact type
250                         artifactTypeId = BackendUtils.getTOSCAcomponentId(ArtifactTypeId.class, artifactTypeStr);
251                         
252                         if (StringUtils.isEmpty(artifactTemplateName) || StringUtils.isEmpty(artifactTemplateNS)) {
253                                 // no explicit name provided
254                                 // we use the artifactNameStr as prefix for the
255                                 // artifact template name
256                                 
257                                 // we create a new artifact template in the namespace of the parent
258                                 // element
259                                 Namespace namespace = this.resWithNamespace.getNamespace();
260                                 
261                                 artifactTemplateId = new ArtifactTemplateId(namespace, new XMLId(artifactNameStr + "artifactTemplate", false));
262                         } else {
263                                 QName artifactTemplateQName = new QName(artifactTemplateNS, artifactTemplateName);
264                                 artifactTemplateId = new ArtifactTemplateId(artifactTemplateQName);
265                         }
266                         ResourceCreationResult creationResult = BackendUtils.create(artifactTemplateId);
267                         if (!creationResult.isSuccess()) {
268                                 // something went wrong. skip
269                                 return creationResult.getResponse();
270                         }
271                         
272                         // associate the type to the created artifact template
273                         artifactTemplateResource = new ArtifactTemplateResource(artifactTemplateId);
274                         // set the type. The resource is automatically persisted inside
275                         artifactTemplateResource.setType(artifactTypeStr);
276                 }
277                 
278                 // variable artifactTypeId is set
279                 // variable artifactTemplateId is not null if artifactTemplate has been generated
280                 
281                 // we have to generate the DA/IA resource now
282                 // Doing it here instead of doing it at the subclasses is dirty on the
283                 // one hand, but quicker to implement on the other hand
284                 
285                 // Create the artifact itself
286                 
287                 ArtifactT resultingArtifact;
288                 
289                 if (this instanceof ImplementationArtifactsResource) {
290                         ImplementationArtifact a = new ImplementationArtifact();
291                         // Winery internal id is the name of the artifact:
292                         // store the name
293                         a.setName(artifactNameStr);
294                         a.setInterfaceName(interfaceNameStr);
295                         a.setOperationName(operationNameStr);
296                         assert (artifactTypeId != null);
297                         a.setArtifactType(artifactTypeId.getQName());
298                         if (artifactTemplateId != null) {
299                                 a.setArtifactRef(artifactTemplateId.getQName());
300                         }
301                         if (doc != null) {
302                                 // the content has been checked for validity at the beginning of the method.
303                                 // If this point in the code is reached, the XML has been parsed into doc
304                                 // just copy over the dom node. Hopefully, that works...
305                                 a.getAny().add(doc.getDocumentElement());
306                         }
307                         
308                         this.list.add((ArtifactT) a);
309                         resultingArtifact = (ArtifactT) a;
310                 } else {
311                         // for comments see other branch
312                         
313                         TDeploymentArtifact a = new TDeploymentArtifact();
314                         a.setName(artifactNameStr);
315                         assert (artifactTypeId != null);
316                         a.setArtifactType(artifactTypeId.getQName());
317                         if (artifactTemplateId != null) {
318                                 a.setArtifactRef(artifactTemplateId.getQName());
319                         }
320                         if (doc != null) {
321                                 a.getAny().add(doc.getDocumentElement());
322                         }
323                         
324                         this.list.add((ArtifactT) a);
325                         resultingArtifact = (ArtifactT) a;
326                 }
327                 
328                 Response persistResponse = BackendUtils.persist(super.res);
329                 // TODO: check for error and in case one found return that
330                 
331                 if (StringUtils.isEmpty(autoGenerateIA)) {
332                         // no IA generation
333                         // we include an XML for the data table
334                         
335                         String implOrDeplArtifactXML = Utils.getXMLAsString(resultingArtifact);
336                         
337                         return Response.created(Utils.createURI(Util.URLencode(artifactNameStr))).entity(implOrDeplArtifactXML).build();
338                 } else {
339                         // after everything was created, we fire up the artifact generation
340                         return this.generateImplementationArtifact(interfaceNameStr, javapackage, uriInfo, artifactTemplateId, artifactTemplateResource);
341                 }
342         }
343         
344         /**
345          * Generates a unique and valid name to be used for the generated maven
346          * project name, java project name, class name, port type name.
347          */
348         private String generateName(NodeTypeId nodeTypeId, String interfaceName) {
349                 String name = Util.namespaceToJavaPackage(nodeTypeId.getNamespace().getDecoded());
350                 name += Util.FORBIDDEN_CHARACTER_REPLACEMENT;
351                 
352                 // Winery already ensures that this is a valid NCName
353                 // getName() returns the id of the nodeType: A nodeType carries the "id" attribute only (and no name attribute)
354                 name += nodeTypeId.getXmlId().getDecoded();
355                 
356                 // Two separators to distinguish node type and interface part
357                 name += Util.FORBIDDEN_CHARACTER_REPLACEMENT;
358                 name += Util.FORBIDDEN_CHARACTER_REPLACEMENT;
359                 name += Util.namespaceToJavaPackage(interfaceName);
360                 
361                 // In addition we must replace '.', because Java class names must not
362                 // contain dots, but for Winery they are fine.
363                 return name.replace(".", Util.FORBIDDEN_CHARACTER_REPLACEMENT);
364         }
365         
366         /**
367          * Generates the implementation artifact using the implementation artifact
368          * generator. Also sets the proeprties according to the requirements of
369          * OpenTOSCA.
370          * 
371          * @param interfaceNameStr
372          * @param javapackage
373          * @param uriInfo
374          * @param artifactTemplateId
375          * @param artifactTemplateResource the resource associated with the
376          *            artifactTempalteId. If null, the object is created in this
377          *            method
378          * 
379          * @return {@inheritDoc}
380          */
381         private Response generateImplementationArtifact(String interfaceNameStr, String javapackage, UriInfo uriInfo, ArtifactTemplateId artifactTemplateId, ArtifactTemplateResource artifactTemplateResource) {
382                 TInterface iface;
383                 
384                 assert (this instanceof ImplementationArtifactsResource);
385                 IHasTypeReference typeRes = (EntityTypeImplementationResource) this.res;
386                 QName type = typeRes.getType();
387                 TOSCAComponentId typeId;
388                 TNodeType nodeType = null;
389                 if (typeRes instanceof NodeTypeImplementationResource) {
390                         // TODO: refactor: This is more a model/repo utilities thing than something which should happen here...
391                         
392                         typeId = new NodeTypeId(type);
393                         NodeTypeResource ntRes = (NodeTypeResource) AbstractComponentsResource.getComponentInstaceResource(typeId);
394                         
395                         // required for IA Generation
396                         nodeType = ntRes.getNodeType();
397                         
398                         List<TInterface> interfaces = nodeType.getInterfaces().getInterface();
399                         Iterator<TInterface> it = interfaces.iterator();
400                         do {
401                                 iface = it.next();
402                                 if (iface.getName().equals(interfaceNameStr)) {
403                                         break;
404                                 }
405                         } while (it.hasNext());
406                         // iface now contains the right interface
407                 } else {
408                         assert (typeRes instanceof RelationshipTypeImplementationResource);
409                         return Response.serverError().entity("IA creation for relation ship type implementations not yet possible").build();
410                 }
411                 
412                 Path workingDir;
413                 try {
414                         workingDir = Files.createTempDirectory("winery");
415                 } catch (IOException e2) {
416                         GenericArtifactsResource.logger.debug("Could not create temporary directory", e2);
417                         return Response.serverError().entity("Could not create temporary directory").build();
418                 }
419                 
420                 URI artifactTemplateFilesUri = uriInfo.getBaseUri().resolve(Utils.getAbsoluteURL(artifactTemplateId)).resolve("files/");
421                 URL artifactTemplateFilesUrl;
422                 try {
423                         artifactTemplateFilesUrl = artifactTemplateFilesUri.toURL();
424                 } catch (MalformedURLException e2) {
425                         GenericArtifactsResource.logger.debug("Could not convert URI to URL", e2);
426                         return Response.serverError().entity("Could not convert URI to URL").build();
427                 }
428                 
429                 String name = this.generateName((NodeTypeId) typeId, interfaceNameStr);
430                 Generator gen = new Generator(iface, javapackage, artifactTemplateFilesUrl, name, workingDir.toFile());
431                 File zipFile = gen.generateProject();
432                 if (zipFile == null) {
433                         return Response.serverError().entity("IA generator failed").build();
434                 }
435                 
436                 // store it
437                 // TODO: refactor: this is more a RepositoryUtils thing than a special thing here; see also importFile at CSARImporter
438                 
439                 ArtifactTemplateDirectoryId fileDir = new ArtifactTemplateDirectoryId(artifactTemplateId);
440                 RepositoryFileReference fref = new RepositoryFileReference(fileDir, zipFile.getName().toString());
441                 try (InputStream is = Files.newInputStream(zipFile.toPath());
442                                 BufferedInputStream bis = new BufferedInputStream(is)) {
443                         String mediaType = Utils.getMimeType(bis, zipFile.getName());
444                         // TODO: do the catch thing as in CSARImporter
445                         
446                         Repository.INSTANCE.putContentToFile(fref, bis, MediaType.valueOf(mediaType));
447                 } catch (IOException e1) {
448                         throw new IllegalStateException("Could not import generated files", e1);
449                 }
450                 
451                 // cleanup dir
452                 try {
453                         FileUtils.forceDelete(workingDir);
454                 } catch (IOException e) {
455                         GenericArtifactsResource.logger.debug("Could not delete working directory", e);
456                 }
457                 
458                 // store the properties in the artifact template
459                 if (artifactTemplateResource == null) {
460                         artifactTemplateResource = (ArtifactTemplateResource) AbstractComponentsResource.getComponentInstaceResource(artifactTemplateId);
461                 }
462                 this.storeProperties(artifactTemplateResource, typeId, name);
463                 
464                 URI url = uriInfo.getBaseUri().resolve(Utils.getAbsoluteURL(fref));
465                 return Response.created(url).build();
466         }
467         
468         
469         private final String NS_OPENTOSCA_WAR_TYPE = "http://www.uni-stuttgart.de/opentosca";
470         
471         
472         private void storeProperties(ArtifactTemplateResource artifactTemplateResource, TOSCAComponentId typeId, String name) {
473                 // We generate the properties by hand instead of using JAX-B as using JAX-B causes issues at org.eclipse.winery.common.ModelUtilities.getPropertiesKV(TEntityTemplate):
474                 // getAny() does not always return "w3c.dom.element" anymore
475                 
476                 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
477                 DocumentBuilder builder;
478                 try {
479                         builder = dbf.newDocumentBuilder();
480                 } catch (ParserConfigurationException e) {
481                         GenericArtifactsResource.logger.error(e.getMessage(), e);
482                         return;
483                 }
484                 Document doc = builder.newDocument();
485                 Element root = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "WSProperties");
486                 doc.appendChild(root);
487                 
488                 Element element = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "ServiceEndpoint");
489                 Text text = doc.createTextNode("/services/" + name + "Port");
490                 element.appendChild(text);
491                 root.appendChild(element);
492                 
493                 element = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "PortType");
494                 text = doc.createTextNode("{" + typeId.getNamespace().getDecoded() + "}" + name);
495                 element.appendChild(text);
496                 root.appendChild(element);
497                 
498                 element = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "InvocationType");
499                 text = doc.createTextNode("SOAP/HTTP");
500                 element.appendChild(text);
501                 root.appendChild(element);
502                 
503                 Properties properties = new Properties();
504                 properties.setAny(root);
505                 PropertiesResource propertiesResource = artifactTemplateResource.getPropertiesResource();
506                 propertiesResource.setProperties(properties);
507         }
508         
509         @Override
510         public Viewable getHTML() {
511                 return new Viewable("/jsp/artifacts/artifacts.jsp", this);
512         }
513         
514         /**
515          * Required for artifacts.jsp
516          * 
517          * @return list of known artifact types.
518          */
519         public List<QName> getAllArtifactTypes() {
520                 SortedSet<ArtifactTypeId> allArtifactTypes = Repository.INSTANCE.getAllTOSCAComponentIds(ArtifactTypeId.class);
521                 List<QName> res = new ArrayList<QName>(allArtifactTypes.size());
522                 for (ArtifactTypeId id : allArtifactTypes) {
523                         res.add(id.getQName());
524                 }
525                 return res;
526         }
527         
528         /**
529          * Required for artifacts.jsp
530          * 
531          * @return list of all contained artifacts.
532          */
533         public abstract Collection<ArtifactResource> getAllArtifactResources();
534         
535         /**
536          * Required by artifact.jsp to decide whether to display
537          * "Deployment Artifact" or "Implementation Artifact"
538          */
539         public boolean getIsDeploymentArtifacts() {
540                 boolean res = (this instanceof DeploymentArtifactsResource);
541                 return res;
542         }
543         
544         /**
545          * required by artifacts.jsp
546          */
547         public String getNamespace() {
548                 return this.resWithNamespace.getNamespace().getDecoded();
549         }
550         
551         /**
552          * For saving resources, an AbstractComponentInstanceResource is required.
553          * DAs may be attached to a node template, which is not an
554          * AbstractComponentInstanceResource, but its grandparent resource
555          * ServiceTemplate is
556          * 
557          * @param res the resource to determine the the
558          *            AbstractComponentInstanceResource for
559          * @return the AbstractComponentInstanceResource where the given res is
560          *         contained in
561          */
562         public static AbstractComponentInstanceResource getAbstractComponentInstanceResource(INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource res) {
563                 final AbstractComponentInstanceResource r;
564                 if (res instanceof NodeTemplateResource) {
565                         r = ((NodeTemplateResource) res).getServiceTemplateResource();
566                 } else {
567                         // quick hack: the resource has to be an abstract component instance
568                         r = (AbstractComponentInstanceResource) res;
569                 }
570                 return r;
571         }
572 }