1 | /* $Id: ModelMemberFilePersister.java 19907 2012-12-30 13:06:01Z closettop_nightlybuild $ | |
2 | ***************************************************************************** | |
3 | * Copyright (c) 2009-2012 Contributors - see below | |
4 | * All rights reserved. This program and the accompanying materials | |
5 | * are made available under the terms of the Eclipse Public License v1.0 | |
6 | * which accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
8 | * | |
9 | * Contributors: | |
10 | * thn | |
11 | * Michiel van der Wulp | |
12 | ***************************************************************************** | |
13 | * | |
14 | * Some portions of this file was previously release using the BSD License: | |
15 | */ | |
16 | ||
17 | // Copyright (c) 1996-2009 The Regents of the University of California. All | |
18 | // Rights Reserved. Permission to use, copy, modify, and distribute this | |
19 | // software and its documentation without fee, and without a written | |
20 | // agreement is hereby granted, provided that the above copyright notice | |
21 | // and this paragraph appear in all copies. This software program and | |
22 | // documentation are copyrighted by The Regents of the University of | |
23 | // California. The software program and documentation are supplied "AS | |
24 | // IS", without any accompanying services from The Regents. The Regents | |
25 | // does not warrant that the operation of the program will be | |
26 | // uninterrupted or error-free. The end-user understands that the program | |
27 | // was developed for research purposes and is advised not to rely | |
28 | // exclusively on the program for any reason. IN NO EVENT SHALL THE | |
29 | // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, | |
30 | // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, | |
31 | // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF | |
32 | // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF | |
33 | // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY | |
34 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
35 | // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE | |
36 | // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF | |
37 | // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, | |
38 | // UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | |
39 | ||
40 | package org.argouml.persistence; | |
41 | ||
42 | import java.io.IOException; | |
43 | import java.io.InputStream; | |
44 | import java.io.OutputStream; | |
45 | import java.net.URL; | |
46 | import java.util.ArrayList; | |
47 | import java.util.Collection; | |
48 | import java.util.HashMap; | |
49 | import java.util.Iterator; | |
50 | import java.util.List; | |
51 | import java.util.logging.Level; | |
52 | import java.util.logging.Logger; | |
53 | ||
54 | import org.argouml.application.api.Argo; | |
55 | import org.argouml.application.helpers.ApplicationVersion; | |
56 | import org.argouml.configuration.Configuration; | |
57 | import org.argouml.kernel.Project; | |
58 | import org.argouml.kernel.ProjectMember; | |
59 | import org.argouml.model.Facade; | |
60 | import org.argouml.model.Model; | |
61 | import org.argouml.model.UmlException; | |
62 | import org.argouml.model.XmiException; | |
63 | import org.argouml.model.XmiReader; | |
64 | import org.argouml.model.XmiWriter; | |
65 | import org.argouml.uml.ProjectMemberModel; | |
66 | import org.argouml.uml.diagram.ArgoDiagram; | |
67 | import org.argouml.uml.diagram.DiagramFactory; | |
68 | import org.argouml.uml.diagram.DiagramFactory.DiagramType; | |
69 | import org.xml.sax.InputSource; | |
70 | ||
71 | /** | |
72 | * The file persister for the UML model. | |
73 | * @author Bob Tarling | |
74 | */ | |
75 | class ModelMemberFilePersister extends MemberFilePersister | |
76 | implements XmiExtensionParser { | |
77 | ||
78 | private static final Logger LOG = | |
79 | Logger.getLogger(ModelMemberFilePersister.class.getName()); | |
80 | ||
81 | private Object curModel; | |
82 | private HashMap<String, Object> uUIDRefs; | |
83 | ||
84 | private Collection elementsRead; | |
85 | ||
86 | /** | |
87 | * Loads a model (XMI only) from a URL. BE ADVISED this | |
88 | * method has a side effect. It sets _UUIDREFS to the model.<p> | |
89 | * | |
90 | * If there is a problem with the xmi file, an error is set in the | |
91 | * getLastLoadStatus() field. This needs to be examined by the | |
92 | * calling function.<p> | |
93 | */ | |
94 | public void load(Project project, URL url) | |
95 | throws OpenException { | |
96 | ||
97 |
1
1. load : removed call to org/argouml/persistence/ModelMemberFilePersister::load → NO_COVERAGE |
load(project, new InputSource(url.toExternalForm())); |
98 | } | |
99 | ||
100 | /** | |
101 | * Loads a model (XMI only) from an input stream. BE ADVISED this | |
102 | * method has a side effect. It sets _UUIDREFS to the model.<p> | |
103 | * | |
104 | * If there is a problem with the xmi file, an error is set in the | |
105 | * getLastLoadStatus() field. This needs to be examined by the | |
106 | * calling function.<p> | |
107 | * | |
108 | * @see org.argouml.persistence.MemberFilePersister#load(org.argouml.kernel.Project, | |
109 | * java.io.InputStream) | |
110 | */ | |
111 | public void load(Project project, InputStream inputStream) | |
112 | throws OpenException { | |
113 | ||
114 |
1
1. load : removed call to org/argouml/persistence/ModelMemberFilePersister::load → NO_COVERAGE |
load(project, new InputSource(inputStream)); |
115 | } | |
116 | ||
117 | ||
118 | public void load(Project project, InputSource source) | |
119 | throws OpenException { | |
120 | ||
121 | Object mmodel = null; | |
122 | ||
123 | // 2002-07-18 | |
124 | // Jaap Branderhorst | |
125 | // changed the loading of the projectfiles to solve hanging | |
126 | // of argouml if a project is corrupted. Issue 913 | |
127 | // Created xmireader with method getErrors to check if parsing went well | |
128 | try { | |
129 |
1
1. load : removed call to org/xml/sax/InputSource::setEncoding → NO_COVERAGE |
source.setEncoding(Argo.getEncoding()); |
130 |
1
1. load : removed call to org/argouml/persistence/ModelMemberFilePersister::readModels → NO_COVERAGE |
readModels(source); |
131 | mmodel = getCurModel(); | |
132 | } catch (OpenException e) { | |
133 | LOG.log(Level.SEVERE, "UmlException caught", e); | |
134 | throw e; | |
135 | } | |
136 | // This should probably be inside xmiReader.parse | |
137 | // but there is another place in this source | |
138 | // where XMIReader is used, but it appears to be | |
139 | // the NSUML XMIReader. When Argo XMIReader is used | |
140 | // consistently, it can be responsible for loading | |
141 | // the listener. Until then, do it here. | |
142 |
1
1. load : removed call to org/argouml/model/UmlHelper::addListenersToModel → NO_COVERAGE |
Model.getUmlHelper().addListenersToModel(mmodel); |
143 | ||
144 | // TODO Add all top level packages | |
145 |
1
1. load : removed call to org/argouml/kernel/Project::addMember → NO_COVERAGE |
project.addMember(mmodel); |
146 | ||
147 |
1
1. load : removed call to org/argouml/kernel/Project::setUUIDRefs → NO_COVERAGE |
project.setUUIDRefs(new HashMap<String, Object>(getUUIDRefs())); |
148 | } | |
149 | ||
150 | /* | |
151 | * @see org.argouml.persistence.MemberFilePersister#getMainTag() | |
152 | */ | |
153 | public String getMainTag() { | |
154 | try { | |
155 |
1
1. getMainTag : mutated return of Object value for org/argouml/persistence/ModelMemberFilePersister::getMainTag to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return Model.getXmiReader().getTagName(); |
156 | } catch (UmlException e) { | |
157 | // Should never happen - something's really wrong | |
158 | throw new RuntimeException(e); | |
159 | } | |
160 | } | |
161 | ||
162 | /** | |
163 | * Save the project model to XMI. | |
164 | * | |
165 | * @see org.argouml.persistence.MemberFilePersister#save(ProjectMember, OutputStream) | |
166 | */ | |
167 | public void save(ProjectMember member, OutputStream outStream) | |
168 | throws SaveException { | |
169 | ||
170 | ProjectMemberModel pmm = (ProjectMemberModel) member; | |
171 | Object model = pmm.getModel(); | |
172 | ||
173 | try { | |
174 | XmiWriter xmiWriter = | |
175 | Model.getXmiWriter(model, outStream, | |
176 | ApplicationVersion.getVersion() + "(" | |
177 | + UmlFilePersister.PERSISTENCE_VERSION + ")"); | |
178 | ||
179 |
1
1. save : removed call to org/argouml/model/XmiWriter::write → NO_COVERAGE |
xmiWriter.write(); |
180 |
1
1. save : removed call to java/io/OutputStream::flush → NO_COVERAGE |
outStream.flush(); |
181 | } catch (UmlException e) { | |
182 | throw new SaveException(e); | |
183 | } catch (IOException e) { | |
184 | throw new SaveException(e); | |
185 | } | |
186 | ||
187 | } | |
188 | ||
189 | public void parse(String label, String xmiExtensionString) { | |
190 | LOG.log(Level.INFO, "Parsing an extension for {0}", label); | |
191 | } | |
192 | ||
193 | ||
194 | /** | |
195 | * @return the current model | |
196 | * @deprecated by tfmorris for 0.33.1 | |
197 | */ | |
198 | @Deprecated | |
199 | public Object getCurModel() { | |
200 |
1
1. getCurModel : mutated return of Object value for org/argouml/persistence/ModelMemberFilePersister::getCurModel to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return curModel; |
201 | } | |
202 | ||
203 | /** | |
204 | * Return XMI id to object map for the most recently read XMI file. | |
205 | * | |
206 | * @return the UUID | |
207 | */ | |
208 | public HashMap<String, Object> getUUIDRefs() { | |
209 |
1
1. getUUIDRefs : mutated return of Object value for org/argouml/persistence/ModelMemberFilePersister::getUUIDRefs to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return uUIDRefs; |
210 | } | |
211 | ||
212 | //////////////////////////////////////////////////////////////// | |
213 | // main parsing methods | |
214 | ||
215 | /** | |
216 | * Read an XMI file from the given URL. | |
217 | * | |
218 | * @param url the URL | |
219 | * @param xmiExtensionParser the XmiExtensionParser | |
220 | * @throws OpenException when there is an IO error | |
221 | */ | |
222 | public synchronized void readModels(URL url, | |
223 | XmiExtensionParser xmiExtensionParser) throws OpenException { | |
224 | LOG.log(Level.INFO, | |
225 | "=======================================\n" | |
226 | +"== READING MODEL {0}", url); | |
227 | ||
228 | try { | |
229 | // TODO: What progressMgr is to be used here? Where does | |
230 | // it come from? | |
231 | InputSource source = | |
232 | new InputSource(new XmiInputStream( | |
233 | url.openStream(), xmiExtensionParser, 100000, null)); | |
234 | ||
235 |
1
1. readModels : removed call to org/xml/sax/InputSource::setSystemId → NO_COVERAGE |
source.setSystemId(url.toString()); |
236 |
1
1. readModels : removed call to org/argouml/persistence/ModelMemberFilePersister::readModels → NO_COVERAGE |
readModels(source); |
237 | } catch (IOException ex) { | |
238 | throw new OpenException(ex); | |
239 | } | |
240 | } | |
241 | ||
242 | /** | |
243 | * Read a XMI file from the given inputsource. | |
244 | * | |
245 | * @param source The InputSource. The systemId of the input source should be | |
246 | * set so that it can be used to resolve external references. | |
247 | * @throws OpenException If an error occur while reading the source | |
248 | */ | |
249 | public synchronized void readModels(InputSource source) | |
250 | throws OpenException { | |
251 | ||
252 | XmiReader reader = null; | |
253 | try { | |
254 | reader = Model.getXmiReader(); | |
255 | ||
256 |
1
1. readModels : negated conditional → NO_COVERAGE |
if (Configuration.getBoolean(Argo.KEY_XMI_STRIP_DIAGRAMS, false)) { |
257 | // TODO: Not implemented by eUML | |
258 | reader.setIgnoredElements(new String[] {"UML:Diagram"}); | |
259 | } else { | |
260 | reader.setIgnoredElements(null); | |
261 | } | |
262 | ||
263 | List<String> searchPath = reader.getSearchPath(); | |
264 | String pathList = | |
265 | System.getProperty("org.argouml.model.modules_search_path"); | |
266 |
1
1. readModels : negated conditional → NO_COVERAGE |
if (pathList != null) { |
267 | String[] paths = pathList.split(","); | |
268 |
3
1. readModels : changed conditional boundary → NO_COVERAGE 2. readModels : Changed increment from 1 to -1 → NO_COVERAGE 3. readModels : negated conditional → NO_COVERAGE |
for (String path : paths) { |
269 |
1
1. readModels : negated conditional → NO_COVERAGE |
if (!searchPath.contains(path)) { |
270 |
1
1. readModels : removed call to org/argouml/model/XmiReader::addSearchPath → NO_COVERAGE |
reader.addSearchPath(path); |
271 | } | |
272 | } | |
273 | } | |
274 |
1
1. readModels : removed call to org/argouml/model/XmiReader::addSearchPath → NO_COVERAGE |
reader.addSearchPath(source.getSystemId()); |
275 | ||
276 | curModel = null; | |
277 | elementsRead = reader.parse(source, false); | |
278 |
2
1. readModels : negated conditional → NO_COVERAGE 2. readModels : negated conditional → NO_COVERAGE |
if (elementsRead != null && !elementsRead.isEmpty()) { |
279 | Facade facade = Model.getFacade(); | |
280 | Object current; | |
281 | Iterator elements = elementsRead.iterator(); | |
282 |
1
1. readModels : negated conditional → NO_COVERAGE |
while (elements.hasNext()) { |
283 | current = elements.next(); | |
284 |
1
1. readModels : negated conditional → NO_COVERAGE |
if (facade.isAModel(current)) { |
285 | if (LOG.isLoggable(Level.INFO)) { | |
286 | LOG.log(Level.INFO, | |
287 | "Loaded model {0}", | |
288 | facade.getName(current)); | |
289 | } | |
290 |
1
1. readModels : negated conditional → NO_COVERAGE |
if (curModel == null) { |
291 | curModel = current; | |
292 | } | |
293 |
1
1. readModels : negated conditional → NO_COVERAGE |
} else if (facade.isAProfile(current)) { |
294 | LOG.log(Level.INFO, | |
295 | "Loaded profile '" + facade.getName(current) | |
296 | + "'"); | |
297 |
1
1. readModels : negated conditional → NO_COVERAGE |
if (curModel == null) { |
298 | curModel = current; | |
299 | } | |
300 | } | |
301 | // TODO: add stereotype application (eCore AnyType?) | |
302 | } | |
303 | } | |
304 | uUIDRefs = | |
305 | new HashMap<String, Object>(reader.getXMIUUIDToObjectMap()); | |
306 | } catch (XmiException ex) { | |
307 | throw new XmiFormatException(ex); | |
308 | } catch (UmlException ex) { | |
309 | // Could this be some other type of internal error that we want | |
310 | // to handle differently? Don't think so. - tfm | |
311 | throw new XmiFormatException(ex); | |
312 | } | |
313 | LOG.log(Level.INFO, "======================================="); | |
314 | } | |
315 | ||
316 | /** | |
317 | * Create and register diagrams for activity and statemachines in the | |
318 | * model(s) of the project. If no other diagrams are created, a default | |
319 | * Class Diagram will be created. ArgoUML currently requires at least one | |
320 | * diagram for proper operation. | |
321 | * | |
322 | * TODO: Move to XmiFilePersister (protected) | |
323 | * | |
324 | * @param project | |
325 | * The project | |
326 | */ | |
327 | public void registerDiagrams(Project project) { | |
328 |
1
1. registerDiagrams : removed call to org/argouml/persistence/ModelMemberFilePersister::registerDiagramsInternal → NO_COVERAGE |
registerDiagramsInternal(project, elementsRead, true); |
329 | } | |
330 | ||
331 | ||
332 | /** | |
333 | * Internal method create diagrams for activity graphs and state machines. | |
334 | * It exists soley to contain common functionality from the two public | |
335 | * methods. It can be merged into its caller when the deprecated version | |
336 | * of the public method goes away. | |
337 | * | |
338 | * @param project | |
339 | * The project | |
340 | * @param elements | |
341 | * Collection of top level model elements to process | |
342 | * @param atLeastOne | |
343 | * If true, forces at least one diagram to be created. | |
344 | */ | |
345 | private void registerDiagramsInternal(Project project, Collection elements, | |
346 | boolean atLeastOne) { | |
347 | Facade facade = Model.getFacade(); | |
348 | Collection diagramsElement = new ArrayList(); | |
349 | Iterator it = elements.iterator(); | |
350 |
1
1. registerDiagramsInternal : negated conditional → NO_COVERAGE |
while (it.hasNext()) { |
351 | Object element = it.next(); | |
352 |
1
1. registerDiagramsInternal : negated conditional → NO_COVERAGE |
if (facade.isAModel(element)) { |
353 | diagramsElement.addAll(Model.getModelManagementHelper() | |
354 | .getAllModelElementsOfKind(element, | |
355 | Model.getMetaTypes().getStateMachine())); | |
356 |
1
1. registerDiagramsInternal : negated conditional → NO_COVERAGE |
} else if (facade.isAStateMachine(element)) { |
357 | diagramsElement.add(element); | |
358 | } | |
359 | } | |
360 | DiagramFactory diagramFactory = DiagramFactory.getInstance(); | |
361 | it = diagramsElement.iterator(); | |
362 |
1
1. registerDiagramsInternal : negated conditional → NO_COVERAGE |
while (it.hasNext()) { |
363 | Object statemachine = it.next(); | |
364 | Object namespace = facade.getNamespace(statemachine); | |
365 |
1
1. registerDiagramsInternal : negated conditional → NO_COVERAGE |
if (namespace == null) { |
366 | namespace = facade.getContext(statemachine); | |
367 |
1
1. registerDiagramsInternal : removed call to org/argouml/model/CoreHelper::setNamespace → NO_COVERAGE |
Model.getCoreHelper().setNamespace(statemachine, namespace); |
368 | } | |
369 | ||
370 | ArgoDiagram diagram = null; | |
371 |
1
1. registerDiagramsInternal : negated conditional → NO_COVERAGE |
if (facade.isAActivityGraph(statemachine)) { |
372 | if (LOG.isLoggable(Level.INFO)) { | |
373 | LOG.log(Level.INFO, | |
374 | "Creating activity diagram for {0}<<{1}>>", | |
375 | new Object[] { | |
376 | facade.getUMLClassName(statemachine), | |
377 | facade.getName(statemachine) | |
378 | }); | |
379 | } | |
380 | diagram = diagramFactory.createDiagram( | |
381 | DiagramType.Activity, | |
382 | namespace, | |
383 | statemachine); | |
384 | } else { | |
385 | if (LOG.isLoggable(Level.INFO)) { | |
386 | LOG.log(Level.INFO, | |
387 | "Creating activity diagram for {0}<<{1}>>", | |
388 | new Object[] { | |
389 | facade.getUMLClassName(statemachine), | |
390 | facade.getName(statemachine) | |
391 | }); | |
392 | } | |
393 | ||
394 | diagram = diagramFactory.createDiagram( | |
395 | DiagramType.State, | |
396 | namespace, | |
397 | statemachine); | |
398 | } | |
399 |
1
1. registerDiagramsInternal : negated conditional → NO_COVERAGE |
if (diagram != null) { |
400 |
1
1. registerDiagramsInternal : removed call to org/argouml/kernel/Project::addMember → NO_COVERAGE |
project.addMember(diagram); |
401 | } | |
402 | ||
403 | } | |
404 | // ISSUE 3516 : Make sure there is at least one diagram because | |
405 | // ArgoUML requires it for correct operation | |
406 |
3
1. registerDiagramsInternal : changed conditional boundary → NO_COVERAGE 2. registerDiagramsInternal : negated conditional → NO_COVERAGE 3. registerDiagramsInternal : negated conditional → NO_COVERAGE |
if (atLeastOne && project.getDiagramCount() < 1) { |
407 | ArgoDiagram d = diagramFactory.create( | |
408 | DiagramType.Class, curModel, | |
409 | project.getProjectSettings().getDefaultDiagramSettings()); | |
410 |
1
1. registerDiagramsInternal : removed call to org/argouml/kernel/Project::addMember → NO_COVERAGE |
project.addMember(d); |
411 | } | |
412 |
2
1. registerDiagramsInternal : changed conditional boundary → NO_COVERAGE 2. registerDiagramsInternal : negated conditional → NO_COVERAGE |
if (project.getDiagramCount() >= 1 |
413 |
1
1. registerDiagramsInternal : negated conditional → NO_COVERAGE |
&& project.getActiveDiagram() == null) { |
414 |
1
1. registerDiagramsInternal : removed call to org/argouml/kernel/Project::setActiveDiagram → NO_COVERAGE |
project.setActiveDiagram( |
415 | project.getDiagramList().get(0)); | |
416 | } | |
417 | } | |
418 | ||
419 | /** | |
420 | * @return Returns the elementsRead. | |
421 | */ | |
422 | public Collection getElementsRead() { | |
423 |
1
1. getElementsRead : mutated return of Object value for org/argouml/persistence/ModelMemberFilePersister::getElementsRead to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return elementsRead; |
424 | } | |
425 | ||
426 | /** | |
427 | * @param elements The elementsRead to set. | |
428 | */ | |
429 | public void setElementsRead(Collection elements) { | |
430 | this.elementsRead = elements; | |
431 | } | |
432 | } | |
Mutations | ||
97 |
1.1 |
|
114 |
1.1 |
|
129 |
1.1 |
|
130 |
1.1 |
|
142 |
1.1 |
|
145 |
1.1 |
|
147 |
1.1 |
|
155 |
1.1 |
|
179 |
1.1 |
|
180 |
1.1 |
|
200 |
1.1 |
|
209 |
1.1 |
|
235 |
1.1 |
|
236 |
1.1 |
|
256 |
1.1 |
|
266 |
1.1 |
|
268 |
1.1 2.2 3.3 |
|
269 |
1.1 |
|
270 |
1.1 |
|
274 |
1.1 |
|
278 |
1.1 2.2 |
|
282 |
1.1 |
|
284 |
1.1 |
|
290 |
1.1 |
|
293 |
1.1 |
|
297 |
1.1 |
|
328 |
1.1 |
|
350 |
1.1 |
|
352 |
1.1 |
|
356 |
1.1 |
|
362 |
1.1 |
|
365 |
1.1 |
|
367 |
1.1 |
|
371 |
1.1 |
|
399 |
1.1 |
|
400 |
1.1 |
|
406 |
1.1 2.2 3.3 |
|
410 |
1.1 |
|
412 |
1.1 2.2 |
|
413 |
1.1 |
|
414 |
1.1 |
|
423 |
1.1 |