1 /*******************************************************************************
2 * Copyright (c) 2013 Pascal Hirmer.
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
10 * Pascal Hirmer - initial API and implementation
11 *******************************************************************************/
13 package org.eclipse.winery.topologymodeler.addons.topologycompleter.helper;
15 import java.io.IOException;
16 import java.io.StringReader;
17 import java.io.StringWriter;
18 import java.util.ArrayList;
19 import java.util.List;
21 import javax.xml.bind.JAXBContext;
22 import javax.xml.bind.JAXBElement;
23 import javax.xml.bind.JAXBException;
24 import javax.xml.bind.Marshaller;
25 import javax.xml.bind.Unmarshaller;
27 import org.eclipse.winery.common.ModelUtilities;
28 import org.eclipse.winery.common.Util;
29 import org.eclipse.winery.model.tosca.Definitions;
30 import org.eclipse.winery.model.tosca.TDefinitions;
31 import org.eclipse.winery.model.tosca.TEntityTemplate;
32 import org.eclipse.winery.model.tosca.TNodeTemplate;
33 import org.eclipse.winery.model.tosca.TRelationshipTemplate;
34 import org.eclipse.winery.model.tosca.TRelationshipTemplate.SourceElement;
35 import org.eclipse.winery.model.tosca.TServiceTemplate;
36 import org.eclipse.winery.model.tosca.TTopologyTemplate;
37 import org.slf4j.LoggerFactory;
39 import com.fasterxml.jackson.databind.ObjectMapper;
40 import com.fasterxml.jackson.databind.type.TypeFactory;
43 * This class contains methods for marshalling and unmarshalling a topology XML string via JAXB.
46 public class JAXBHelper {
48 private static final org.slf4j.Logger logger = LoggerFactory.getLogger(JAXBHelper.class.getName());
51 * This constant is used in the buildXML method which add coordinates to Node Templates so they
52 * are arranged properly in the Winery topology modeler.
54 * The x coordinate is constant because it is assumed that a stack of NodeTemplates is displayed.
56 private static final String NODETEMPLATE_X_COORDINATE = "500";
59 * This method creates an JAXB Unmarshaller used by the methods contained in this class.
61 * @return the JAXB unmarshaller object
63 * @throws JAXBException
64 * this exception can occur when the JAXBContext is created
66 private static Unmarshaller createUnmarshaller() throws JAXBException {
67 // initiate JaxB context
69 context = JAXBContext.newInstance(Definitions.class);
71 return context.createUnmarshaller();
75 * This method returns a {@link TTopologyTemplate} given as XML string as JaxBObject.
78 * the {@link TTopologyTemplate} to be unmarshalled
80 * @return the unmarshalled {@link TTopologyTemplate}
82 public static TTopologyTemplate getTopologyAsJaxBObject(String xmlString) {
85 logger.info("Getting Definitions Document...");
87 StringReader reader = new StringReader(xmlString);
89 // unmarshall the XML string
90 Definitions jaxBDefinitions = (Definitions) createUnmarshaller().unmarshal(reader);
91 TServiceTemplate serviceTemplate = (TServiceTemplate) jaxBDefinitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0);
93 logger.info("Unmarshalling successful! ");
95 return serviceTemplate.getTopologyTemplate();
97 } catch (JAXBException e) {
98 logger.error(e.getLocalizedMessage());
104 * This method returns {@link TRelationshipTemplate}s as a JaxBObject.
107 * the {@link TRelationshipTemplate} to be unmarshalled
109 * @return the unmarshalled {@link TRelationshipTemplate}
111 public static List<TRelationshipTemplate> getRelationshipTemplatesAsJaxBObject(String xmlString) {
113 StringReader reader = new StringReader(xmlString);
116 Definitions jaxBDefinitions = (Definitions) createUnmarshaller().unmarshal(reader);
117 TServiceTemplate serviceTemplate = (TServiceTemplate) jaxBDefinitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0);
119 List<TRelationshipTemplate> foundRTs = new ArrayList<>();
120 for (TEntityTemplate entity : serviceTemplate.getTopologyTemplate().getNodeTemplateOrRelationshipTemplate()) {
121 if (entity instanceof TRelationshipTemplate) {
122 foundRTs.add((TRelationshipTemplate) entity);
128 } catch (JAXBException e) {
129 logger.error(e.getLocalizedMessage());
136 * Turns XML Strings into {@link TEntityTemplate} objects using JaxB.
139 * the XMLString to be parsed
140 * @return the parsed XMLString as {@link TEntityTemplate}
142 public static List<TEntityTemplate> getEntityTemplatesAsJaxBObject(String xmlString) {
144 StringReader reader = new StringReader(xmlString);
146 Definitions jaxBDefinitions = (Definitions) createUnmarshaller().unmarshal(reader);
147 TServiceTemplate serviceTemplate = (TServiceTemplate) jaxBDefinitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0);
149 return serviceTemplate.getTopologyTemplate().getNodeTemplateOrRelationshipTemplate();
151 } catch (JAXBException e) {
152 logger.error(e.getLocalizedMessage());
159 * Converts any object of the TOSCA data model to a JaxBObject.
162 * the {@link Definitions} object to be converted
164 * @return the unmarshalled {@link Definitions} object
166 public static Definitions getXasJaxBObject(String xmlString) {
168 StringReader reader = new StringReader(xmlString);
169 Definitions jaxBDefinitions = (Definitions) createUnmarshaller().unmarshal(reader);
171 return jaxBDefinitions;
173 } catch (JAXBException e) {
174 logger.error(e.getLocalizedMessage());
181 * This method adds a selection of {@link TNodeTemplate}- and {@link TRelationshipTemplate}-XML-Strings to a {@link TTopologyTemplate}-XML-String using JAXB.
182 * After the templates have been added, the {@link TTopologyTemplate} object is re-marshalled to an XML-String.
184 * This method is called by the selectionHandler.jsp after several Node or RelationshipTemplates have been chosen in a dialog.
187 * the topology as XML string
188 * @param allTemplateChoicesAsXML
189 * all possible template choices as TOSCA-XML strings containing the complete templates
190 * @param selectedNodeTemplatesAsJSON
191 * the names of the selected NodeTemplates as JSONArray
192 * @param selectedRelationshipTemplatesAsJSON
193 * the names of the selected RelationshipTemplates as JSONArray
195 * @return the complete topology XML string
197 public static String addTemplatesToTopology(String topology, String allTemplateChoicesAsXML, String selectedNodeTemplatesAsJSON, String selectedRelationshipTemplatesAsJSON) {
200 // initialization code for the jackson types used to convert JSON string arrays to a java.util.List
201 ObjectMapper mapper = new ObjectMapper();
202 TypeFactory factory = mapper.getTypeFactory();
204 // convert the JSON array containing the names of the selected RelationshipTemplates to a java.util.List
205 List<String> selectedRelationshipTemplates = mapper.readValue(selectedRelationshipTemplatesAsJSON, factory.constructCollectionType(List.class, String.class));
207 // convert the topology and the choices to objects using JAXB
208 TTopologyTemplate topologyTemplate = getTopologyAsJaxBObject(topology);
209 List<TEntityTemplate> allTemplateChoices = getEntityTemplatesAsJaxBObject(allTemplateChoicesAsXML);
211 // this distinction of cases is necessary because it is possible that only RelationshipTemplates have been selected
212 if (selectedNodeTemplatesAsJSON != null) {
214 // convert the JSON string array containing the names of the selected NodeTemplates to a java.util.List
215 List<String> selectedNodeTemplates = mapper.readValue(selectedNodeTemplatesAsJSON, factory.constructCollectionType(List.class, String.class));
217 // search the selected NodeTemplate in the List of all choices by its name to receive its object which will ne added to the topology
218 for (String nodeTemplateName : selectedNodeTemplates) {
219 for (TEntityTemplate choice : allTemplateChoices) {
220 if (choice instanceof TNodeTemplate) {
221 TNodeTemplate nodeTemplate = (TNodeTemplate) choice;
222 // matching a name is usually unsafe because the uniqueness cannot be assured,
223 // however similar names are not possible at this location due to the implementation of the selection dialogs
224 if (nodeTemplateName.equals(nodeTemplate.getName())) {
225 // add the selected NodeTemplate to the topology
226 topologyTemplate.getNodeTemplateOrRelationshipTemplate().add(nodeTemplate);
228 // due to the mapping of IDs in the selection dialog, the corresponding Relationship Template of the inserted Node Template misses its SourceElement.
229 // Re-add it to avoid errors.
230 for (TEntityTemplate entity: topologyTemplate.getNodeTemplateOrRelationshipTemplate()) {
231 if (entity instanceof TRelationshipTemplate) {
232 TRelationshipTemplate relationshipTemplate = (TRelationshipTemplate) entity;
233 if (relationshipTemplate.getSourceElement().getRef() == null) {
234 // connect to the added NodeTemplate
235 SourceElement sourceElement = new SourceElement();
236 sourceElement.setRef(nodeTemplate);
237 relationshipTemplate.setSourceElement(sourceElement);
246 // now search and add the selected RelationshipTemplate object connecting to the inserted NodeTemplate
247 for (String relationshipTemplateName : selectedRelationshipTemplates) {
248 for (TEntityTemplate toBeAdded : allTemplateChoices) {
249 if (toBeAdded instanceof TRelationshipTemplate) {
250 TRelationshipTemplate relationshipTemplate = (TRelationshipTemplate) toBeAdded;
251 if (relationshipTemplateName.equals(relationshipTemplate.getName())) {
252 topologyTemplate.getNodeTemplateOrRelationshipTemplate().add(relationshipTemplate);
259 // in this case only Relationship Templates have been selected
260 List<TRelationshipTemplate> allRelationshipTemplateChoices = JAXBHelper.getRelationshipTemplatesAsJaxBObject(allTemplateChoicesAsXML);
262 // add the target Node Template to the topology which is unique due to the implementation of the selection dialog
263 topologyTemplate.getNodeTemplateOrRelationshipTemplate().add((TNodeTemplate) ((TRelationshipTemplate) allRelationshipTemplateChoices.get(0)).getTargetElement().getRef());
265 // search the JAXB object of the selected RelationshipTemplate and add it to the topology
266 for (String relationshipTemplateName : selectedRelationshipTemplates) {
267 for (TRelationshipTemplate choice : allRelationshipTemplateChoices) {
268 if (relationshipTemplateName.equals(choice.getName())) {
269 topologyTemplate.getNodeTemplateOrRelationshipTemplate().add(choice);
274 for (TEntityTemplate entityTemplate : topologyTemplate.getNodeTemplateOrRelationshipTemplate()) {
275 if (entityTemplate instanceof TRelationshipTemplate) {
276 TRelationshipTemplate relationship = (TRelationshipTemplate) entityTemplate;
278 // due to the mapping of IDs in the selection dialog, the corresponding Relationship Template of the inserted Node Template misses its SourceElement.
279 // Re-add it to avoid errors.
280 if (relationship.getSourceElement().getRef() == null) {
281 relationship.getSourceElement().setRef((TNodeTemplate) ((TRelationshipTemplate) allRelationshipTemplateChoices.get(0)).getTargetElement().getRef());
287 // re-convert the topology from a JAXB object to an XML string and return it
288 Definitions definitions = new Definitions();
289 TServiceTemplate st = new TServiceTemplate();
290 st.setTopologyTemplate(topologyTemplate);
291 definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().add(st);
292 JAXBContext context = JAXBContext.newInstance(Definitions.class);
293 Marshaller m = context.createMarshaller();
294 StringWriter stringWriter = new StringWriter();
296 m.marshal(definitions, stringWriter);
298 return stringWriter.toString();
300 } catch (JAXBException | IOException e) {
301 logger.error(e.getLocalizedMessage());
309 * Marshalls a JAXB object of the TOSCA model to an XML string.
312 * the class of the object
314 * the object to be marshalled
318 public static String getXMLAsString(@SuppressWarnings("rawtypes") Class clazz, Object obj) {
320 @SuppressWarnings("rawtypes")
321 JAXBElement rootElement = Util.getJAXBElement(clazz, obj);
322 JAXBContext context = JAXBContext.newInstance(TDefinitions.class);
325 m = context.createMarshaller();
327 StringWriter w = new StringWriter();
328 m.marshal(rootElement, w);
329 String res = w.toString();
332 } catch (JAXBException e) {
333 logger.error(e.getLocalizedMessage());
339 * This methods alters the XML with JAXB so it can be imported in Winery. This is necessary because Winery needs additional information for the position of the templates in the
342 * This code is adapted from the org.eclipse.winery.repository.Utils.getXMLAsString() method.
345 * the {@link TTopologyTemplate} to be altered
347 * @return the altered {@link TTopologyTemplate}
349 public static TTopologyTemplate buildXML(TTopologyTemplate topology) {
351 // the coordinate of the NodeTemplate in Winery. Begin 100 pixel from the top to improve arrangement.
352 int yCoordinates = 100;
354 for (TEntityTemplate template : topology.getNodeTemplateOrRelationshipTemplate()) {
355 // add node templates
356 if (template instanceof TNodeTemplate) {
358 TNodeTemplate nodeTemplate = (TNodeTemplate) template;
360 // remove the Requirements tag if necessary
361 if (nodeTemplate.getRequirements() != null && nodeTemplate.getRequirements().getRequirement() == null) {
362 nodeTemplate.setRequirements(null);
365 ModelUtilities.setLeft(nodeTemplate, NODETEMPLATE_X_COORDINATE);
366 ModelUtilities.setTop(nodeTemplate, Integer.toString(yCoordinates));