Merge "Fix build errors in autorelease full clean build"
[vfc/nfvo/wfengine.git] / winery / org.eclipse.winery.repository / src / main / java / org / eclipse / winery / repository / resources / imports / xsdimports / XSDImportResource.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.imports.xsdimports;
13
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.Date;
20 import java.util.List;
21
22 import javax.ws.rs.GET;
23 import javax.ws.rs.Produces;
24 import javax.ws.rs.core.MediaType;
25 import javax.ws.rs.core.Response;
26 import javax.ws.rs.core.Response.Status;
27 import javax.xml.XMLConstants;
28
29 import org.apache.xerces.xs.XSConstants;
30 import org.apache.xerces.xs.XSModel;
31 import org.apache.xerces.xs.XSNamedMap;
32 import org.apache.xerces.xs.XSObject;
33 import org.eclipse.winery.common.RepositoryFileReference;
34 import org.eclipse.winery.common.ids.definitions.imports.XSDImportId;
35 import org.eclipse.winery.model.tosca.TExtensibleElements;
36 import org.eclipse.winery.model.tosca.TImport;
37 import org.eclipse.winery.repository.Utils;
38 import org.eclipse.winery.repository.backend.BackendUtils;
39 import org.eclipse.winery.repository.backend.Repository;
40 import org.eclipse.winery.repository.resources.imports.genericimports.GenericImportResource;
41 import org.restdoc.annotations.RestDoc;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 import com.fasterxml.jackson.core.JsonProcessingException;
46
47 /**
48  * Even if we are not a component instance, we use that infrastructure to manage
49  * imports. Some hacks will be necessary. However, these are less effort than
50  * doing a clean design
51  */
52 public class XSDImportResource extends GenericImportResource {
53         
54         private static final Logger logger = LoggerFactory.getLogger(XSDImportResource.class);
55         
56         
57         public XSDImportResource(XSDImportId id) {
58                 super(id);
59         }
60         
61         @Override
62         protected TExtensibleElements createNewElement() {
63                 TImport imp = new TImport();
64                 imp.setImportType(XMLConstants.W3C_XML_SCHEMA_NS_URI);
65                 return imp;
66         }
67         
68         /**
69          * public required by XSDImportsResource
70          * 
71          * @return null if XSD file does not exist
72          */
73         public RepositoryFileReference getXSDFileReference() {
74                 String loc = this.getLocation();
75                 if (loc == null) {
76                         return null;
77                 }
78                 final RepositoryFileReference ref = new RepositoryFileReference(this.id, loc);
79                 return ref;
80         }
81         
82         /**
83          * @return null if no file is associated
84          */
85         private XSModel getXSModel() {
86                 final RepositoryFileReference ref = this.getXSDFileReference();
87                 return BackendUtils.getXSModel(ref);
88         }
89         
90         // we need "unchecked", because of the parsing of the cache
91         @SuppressWarnings("unchecked")
92         public Collection<String> getAllDefinedLocalNames(short type) {
93                 RepositoryFileReference ref = this.getXSDFileReference();
94                 if (ref == null) {
95                         return Collections.emptySet();
96                 }
97                 Date lastUpdate = Repository.INSTANCE.getLastUpdate(ref);
98                 
99                 String cacheFileName = "definedLocalNames " + Integer.toString(type) + ".cache";
100                 RepositoryFileReference cacheRef = new RepositoryFileReference(this.id, cacheFileName);
101                 boolean cacheNeedsUpdate = true;
102                 if (Repository.INSTANCE.exists(cacheRef)) {
103                         Date lastUpdateCache = Repository.INSTANCE.getLastUpdate(cacheRef);
104                         if (lastUpdate.compareTo(lastUpdateCache) <= 0) {
105                                 cacheNeedsUpdate = false;
106                         }
107                 }
108                 
109                 List<String> result;
110                 if (cacheNeedsUpdate) {
111                         
112                         XSModel model = this.getXSModel();
113                         if (model == null) {
114                                 return Collections.emptySet();
115                         }
116                         XSNamedMap components = model.getComponents(type);
117                         //@SuppressWarnings("unchecked")
118                         int len = components.getLength();
119                         result = new ArrayList<String>(len);
120                         for (int i = 0; i < len; i++) {
121                                 XSObject item = components.item(i);
122                                 // if queried for TYPE_DEFINITION, then XSD base types (such as IDREF) are also returned
123                                 // We want to return only types defined in the namespace of this resource
124                                 if (item.getNamespace().equals(this.id.getNamespace().getDecoded())) {
125                                         result.add(item.getName());
126                                 }
127                         }
128                         
129                         String cacheContent = null;
130                         try {
131                                 cacheContent = Utils.mapper.writeValueAsString(result);
132                         } catch (JsonProcessingException e) {
133                                 XSDImportResource.logger.error("Could not generate cache content", e);
134                         }
135                         try {
136                                 Repository.INSTANCE.putContentToFile(cacheRef, cacheContent, MediaType.APPLICATION_JSON_TYPE);
137                         } catch (IOException e) {
138                                 XSDImportResource.logger.error("Could not update cache", e);
139                         }
140                 } else {
141                         // read content from cache
142                         // cache should contain most recent information
143                         try (InputStream is = Repository.INSTANCE.newInputStream(cacheRef)) {
144                                 result = Utils.mapper.readValue(is, java.util.List.class);
145                         } catch (IOException e) {
146                                 XSDImportResource.logger.error("Could not read from cache", e);
147                                 result = Collections.emptyList();
148                         }
149                 }
150                 return result;
151         }
152         
153         public Collection<String> getAllDefinedElementsLocalNames() {
154                 return this.getAllDefinedLocalNames(XSConstants.ELEMENT_DECLARATION);
155         }
156         
157         public Collection<String> getAllDefinedTypesLocalNames() {
158                 return this.getAllDefinedLocalNames(XSConstants.TYPE_DEFINITION);
159         }
160         
161         @GET
162         @RestDoc(methodDescription = "May be used by the modeler to generate an XML editor based on the XML schema")
163         // we cannot use "MimeTypes.MIMETYPE_XSD" here as the latter is "text/xml" and org.eclipse.winery.repository.resources.AbstractComponentInstanceResource.getDefinitionsAsResponse() also produces text/xml
164         @Produces("text/xsd")
165         public Response getXSD() {
166                 String location;
167                 if ((location = this.getLocation()) == null) {
168                         return Response.status(Status.NOT_FOUND).build();
169                 }
170                 RepositoryFileReference ref = new RepositoryFileReference(this.id, location);
171                 return BackendUtils.returnRepoPath(ref, null);
172         }
173         
174 }