View Javadoc

1   /*
2    *  Copyright (C) 2003-2005 SINTEF
3    *  Author:  Fredrik Vraalsen (fredrik dot vraalsen at sintef dot no)
4    *  Webpage: http://coras.sourceforge.net/
5    *
6    *  This program is free software; you can redistribute it and/or
7    *  modify it under the terms of the GNU Lesser General Public License
8    *  as published by the Free Software Foundation; either version 2.1
9    *  of the License, or (at your option) any later version.
10   *
11   *  This program is distributed in the hope that it will be useful,
12   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   *  Lesser General Public License for more details.
15   *
16   *  You should have received a copy of the GNU Lesser General Public
17   *  License along with this program; if not, write to the Free
18   *  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19   *  02111-1307 USA
20   */
21  package coras.internalmodel;
22  
23  import java.io.ByteArrayInputStream;
24  import java.io.IOException;
25  import java.net.URL;
26  import java.util.Calendar;
27  import java.util.Collection;
28  import java.util.Iterator;
29  
30  import javax.xml.parsers.ParserConfigurationException;
31  import javax.xml.transform.Transformer;
32  import javax.xml.transform.dom.DOMResult;
33  import javax.xml.transform.dom.DOMSource;
34  
35  import no.sintef.assetrepository.Asset;
36  import no.sintef.assetrepository.Representation;
37  import no.sintef.assetrepository.interfaces.AssetRepresentationPK;
38  import no.sintef.assetrepository.interfaces.AssetRepresentationValue;
39  import no.sintef.assetrepository.interfaces.AssetServices;
40  import no.sintef.assetrepository.interfaces.AssetVersionValue;
41  import no.sintef.file.MimeTypeEnum;
42  import no.sintef.lock.AlreadyLockedException;
43  import no.sintef.umt.XmiLightTransformer;
44  import no.sintef.umt.XmiReader;
45  import no.sintef.xml.XmlException;
46  import no.sintef.xml.XmlHelper;
47  
48  import org.apache.log4j.Logger;
49  import org.w3c.dom.Document;
50  import org.w3c.dom.Element;
51  import org.w3c.dom.Node;
52  import org.xml.sax.SAXException;
53  
54  import coras.dgm.DgmTransformer;
55  import coras.representations.RepresentationTypeEnum;
56  import coras.types.ElementTypeEnum;
57  import coras.types.SubtypeEnum;
58  
59  
60  /***
61   * @author fvr
62   *
63   * To change the template for this generated type comment go to
64   * Window - Preferences - Java - Code Generation - Code and Comments
65   */
66  public class InternalModelFactory {
67  	
68  	
69  	private static final Logger LOGGER = Logger.getLogger(InternalModelFactory.class);
70  	
71  	private static final String NAMESPACE_URI = "http://coras.sourceforge.net/schemas/coras-internalmodel-1_0.xsd";
72  	private static final String PREFIX = "ci";
73  	private static final String ROOT_ELEM = "riskAssessmentDocuments";
74  	// private static final String TABLE_ELEM = "table";
75  	
76  	private static InternalModelFactory theFactory = null;
77  	
78  	// TODO : use ThreadLocal to avoid synchronized access to transformers...
79  	private Transformer internalTransformer = null;
80  	
81  
82  	public static synchronized InternalModelFactory getInternalModelFactory() {
83  		if (theFactory == null) {
84  			try {
85  				theFactory = new InternalModelFactory();
86  			} catch (Exception e) {
87  				LOGGER.warn("Could not create InternalModelFactory: " + e);
88  				e.printStackTrace();
89  				theFactory = null;
90  			}
91  		}
92  		return theFactory;
93  	}
94  	
95  	
96  	private InternalModelFactory() throws ParserConfigurationException, IOException, SAXException {
97  		ClassLoader cl = getClass().getClassLoader();
98  		URL url = cl.getResource("coras/internalmodel/CorasXml2InternalXml.xsl");
99  		// LOGGER.debug("url = " + url);
100 		try {
101 			// Document internalXslDoc = XmlHelper.parse(new InputSource(url.openStream()));
102 			internalTransformer = XmlHelper.getTransformer(url, LOGGER);
103 		} catch (XmlException e) {
104 			LOGGER.fatal("Unable to create CorasXml2InternalXml transformer", e);
105 		}
106 	}
107 	
108 	
109 	public Element getInternalRepresentation(Collection resultVersions, AssetServices services) {
110 		if (resultVersions == null)
111 			return null;
112 		
113 		Document doc = XmlHelper.createDocument(NAMESPACE_URI, PREFIX, ROOT_ELEM, null);
114 		Element rootElem = doc.getDocumentElement();
115 		
116 		for (Iterator i = resultVersions.iterator(); i.hasNext(); ) {
117 		    
118 			AssetVersionValue resultVersion = (AssetVersionValue) i.next();
119 			Node n = getInternalRepresentation(resultVersion, services);
120 			n = XmlHelper.getRootElement(n);
121 			if (n != null) {
122 				rootElem.appendChild(doc.importNode(n, true));
123 			}
124 		}
125 		
126 		if (LOGGER.isDebugEnabled()) {
127 			LOGGER.debug("internal model source: " + new String(XmlHelper.xmlToUtf8(rootElem, true)));
128 		}
129 		DOMSource source = new DOMSource(rootElem);
130 		DOMResult result = new DOMResult();
131 		try {
132 			synchronized (internalTransformer) {
133 				internalTransformer.transform(source, result);
134 			}
135 			if (LOGGER.isDebugEnabled()) {
136 				LOGGER.debug("internal model: " + new String(XmlHelper.xmlToUtf8(result.getNode(), true)));
137 			}
138 			return XmlHelper.getRootElement(result.getNode());
139 		} catch (Exception e) {
140 			LOGGER.warn("Could not create internal representation: " + e);
141 			e.printStackTrace();
142 			return null;
143 		}
144 	}
145 
146 
147 	/***
148 	 * @param resultVersion
149 	 * @return
150 	 */
151 	private Node getInternalRepresentation(AssetVersionValue resultVersion, AssetServices services) {
152 		if (resultVersion == null)
153 			return null;
154 		ElementTypeEnum type = ElementTypeEnum.forName((String) resultVersion.getProperties().get("type")); // resultVersion.getType();
155 		SubtypeEnum subtype = SubtypeEnum.forName((String) resultVersion.getProperties().get("subtype")); // resultVersion.getSubtype();
156 		if (type == null) {
157 			return null;
158 		}
159 		if (type == ElementTypeEnum.TABLE || type == ElementTypeEnum.FAULT_TREE) {
160 		    Object content;
161 		    if (type == ElementTypeEnum.TABLE) {
162 		        content = getRepresentationContent(resultVersion, RepresentationTypeEnum.TABLE, services);
163 		    } else {
164 		        content = getRepresentationContent(resultVersion, RepresentationTypeEnum.FAULT_TREE_MODEL, services);
165 		    }
166 			if (content instanceof Node) {
167 				return (Node) content;
168 			} else if (content == null) {
169 			    if (type == ElementTypeEnum.TABLE) {
170 			        LOGGER.error("No table content");
171 			    }
172 			    return null;
173 			} else {
174 				LOGGER.warn(type + " content not XML");
175 				return null;
176 			}
177 		} else if (type == ElementTypeEnum.UML_MODEL) {
178 			Node xmiLight = getXmiLight(resultVersion, services, subtype);
179 			if (LOGGER.isDebugEnabled()) {
180 				LOGGER.debug("XMI Light: " + new String(XmlHelper.xmlToUtf8(xmiLight, true)));
181 			}
182 			return xmiLight;
183 		} else {
184 			return null;
185 		}
186 	}
187 
188 	
189 	private Node getXmiLight(AssetVersionValue resultVersion, AssetServices services, SubtypeEnum subtype) {
190 		Object content = getRepresentationContent(resultVersion, RepresentationTypeEnum.XMI_LIGHT, services);
191 		if (content instanceof Node) {
192 			if (LOGGER.isDebugEnabled()) {
193 				LOGGER.debug("Found XMI Light representation for UML model asset " + resultVersion.getAsset());
194 			}
195 			return (Node) content;
196 		}
197 		
198 		Node xmiLight = generateXmiLight(resultVersion, services, subtype);
199 		if (LOGGER.isDebugEnabled()) {
200 			LOGGER.debug("Generated XMI Light representation for UML model asset " + resultVersion.getAsset() 
201 					+ ":\n" + new String(XmlHelper.xmlToUtf8(xmiLight, true)));
202 		}
203 		if (xmiLight != null) {
204 			// autocreate an XMI light representation...
205 			try {
206 				Representation xmiLightRepresentation = 
207 					Representation.create(RepresentationTypeEnum.XMI_LIGHT.toString(),
208 							null,
209 							MimeTypeEnum.TEXT_XML,
210 							xmiLight,
211 							Calendar.getInstance());
212 				Asset asset = Asset.getAssetById(resultVersion.getAsset().getId());
213 				boolean alreadyCheckedOut = false;
214 				try {
215 					asset.checkOut();
216 				} catch (AlreadyLockedException e) {
217 					alreadyCheckedOut = true;
218 				}
219 				asset.addRepresentation(xmiLightRepresentation);
220 				// FIXME: is this correct checkin/checkout?
221 				asset.checkIn("Added XMI light representation");
222 				if (alreadyCheckedOut) {
223 					asset.checkOut();
224 				}
225 			} catch (Exception e) {
226 				LOGGER.warn("Unable to add XMI light representation to UML model asset " + resultVersion.getAsset(), e);
227 			}
228 		}
229 		return xmiLight;
230 	}
231 
232 	private Node generateXmiLight(AssetVersionValue resultVersion, AssetServices services, SubtypeEnum subtype) {
233 		Node xmiLight = null;
234 		Object content = getRepresentationContent(resultVersion, RepresentationTypeEnum.DGM_MODEL, services);
235 		if (content != null) {
236 			if (!(content instanceof Node)) {
237 				LOGGER.warn("CORAS UML model content not XML");
238 				return null;
239 			}
240 			xmiLight = DgmTransformer.getTransformer().getXmiLight((Node) content);
241 		} else {
242 			content = getRepresentationContent(resultVersion, RepresentationTypeEnum.XMI_MODEL, services);
243 			if (content != null) {
244 				if (!(content instanceof Node)) {
245 					LOGGER.warn("XMI model content not XML");
246 					return null;
247 				}
248 				xmiLight = XmiLightTransformer.getTransformer().getXmiLight((Node) content);
249 			} else {
250 				content = getRepresentationContent(resultVersion, RepresentationTypeEnum.ZUMLZARGO_MODEL, services);
251 				if (content instanceof byte[]) {
252 					try {
253 						Node xmi = XmiReader.getZumlZargoXmi(new ByteArrayInputStream((byte[]) content));
254 						xmiLight = XmiLightTransformer.getTransformer().getXmiLight(xmi);
255 					} catch (Exception e) {
256 						LOGGER.warn("Unable to extract XMI from Poseidon/ArgoUML model", e);
257 					}
258 				} else {
259 					return null;
260 				}
261 			}
262 		}
263 		Element rootElem = XmlHelper.getRootElement(xmiLight);
264 		if (rootElem != null) {
265 			rootElem.setAttribute("type", subtype.toString());
266 		}
267 		return rootElem;
268 	}
269 
270 	/***
271 	 * @param resultVersion
272 	 * @param string
273 	 * @return
274 	 */
275 	private Object getRepresentationContent(AssetVersionValue resultVersion, RepresentationTypeEnum type, AssetServices services) {
276 		// System.out.println("getRepresentationContent for type " + type);
277 		if (resultVersion == null || type == null)
278 			return null;
279 		Collection representations = resultVersion.getRepresentations();
280 		if (representations == null)
281 			return null;
282 		for (Iterator i = representations.iterator(); i.hasNext(); ) {
283 			AssetRepresentationPK representationPK = (AssetRepresentationPK) i.next();
284 			try {
285 			    AssetRepresentationValue representation = services.getAssetRepresentation(representationPK);
286 			    // System.out.println("representation[" + representation.getName() + "]: " + representation.getType() + " content type " + representation.getContent().getClass());
287 			    if (type == RepresentationTypeEnum.forName(representation.getType())) {
288 			        return representation.getContent();
289 			    }
290 			} catch (Exception e) {
291 			    e.printStackTrace();
292 			}
293 		}
294 		return null;
295 	}
296 	
297 	
298 }