1 | /* $Id: XmiFilePersister.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 | * tfmorris | |
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-2008 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.ByteArrayInputStream; | |
43 | import java.io.File; | |
44 | import java.io.FileNotFoundException; | |
45 | import java.io.FileOutputStream; | |
46 | import java.io.IOException; | |
47 | import java.io.InputStream; | |
48 | import java.io.OutputStream; | |
49 | import java.io.StringReader; | |
50 | import java.util.ArrayList; | |
51 | import java.util.List; | |
52 | import java.util.logging.Level; | |
53 | import java.util.logging.Logger; | |
54 | ||
55 | import org.argouml.i18n.Translator; | |
56 | import org.argouml.kernel.Project; | |
57 | import org.argouml.kernel.ProjectFactory; | |
58 | import org.argouml.kernel.ProjectManager; | |
59 | import org.argouml.kernel.ProjectMember; | |
60 | import org.argouml.model.Model; | |
61 | import org.argouml.uml.cognitive.ProjectMemberTodoList; | |
62 | import org.argouml.util.ThreadUtils; | |
63 | import org.xml.sax.InputSource; | |
64 | ||
65 | /** | |
66 | * To persist to and from XMI file storage. | |
67 | * | |
68 | * @author Bob Tarling | |
69 | */ | |
70 | class XmiFilePersister extends AbstractFilePersister | |
71 | implements XmiExtensionParser { | |
72 | /** | |
73 | * Logger. | |
74 | */ | |
75 | private static final Logger LOG = | |
76 | Logger.getLogger(XmiFilePersister.class.getName()); | |
77 | ||
78 | private List<String> pgmlStrings = new ArrayList<String>(); | |
79 | ||
80 | private String todoString; | |
81 | ||
82 | private String argoString; | |
83 | ||
84 | /** | |
85 | * The constructor. | |
86 | */ | |
87 | public XmiFilePersister() { | |
88 | } | |
89 | ||
90 | /* | |
91 | * @see org.argouml.persistence.AbstractFilePersister#getExtension() | |
92 | */ | |
93 | public String getExtension() { | |
94 |
1
1. getExtension : mutated return of Object value for org/argouml/persistence/XmiFilePersister::getExtension to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return "xmi"; |
95 | } | |
96 | ||
97 | /* | |
98 | * @see org.argouml.persistence.AbstractFilePersister#getDesc() | |
99 | */ | |
100 | protected String getDesc() { | |
101 |
1
1. getDesc : mutated return of Object value for org/argouml/persistence/XmiFilePersister::getDesc to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return Translator.localize("combobox.filefilter.xmi"); |
102 | } | |
103 | ||
104 | /* | |
105 | * @see org.argouml.persistence.AbstractFilePersister#isSaveEnabled() | |
106 | */ | |
107 | public boolean isSaveEnabled() { | |
108 |
1
1. isSaveEnabled : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE |
return false; |
109 | } | |
110 | ||
111 | /** | |
112 | * Save a project to a file in XMI format. | |
113 | * | |
114 | * @param project the project to save. | |
115 | * @param file The file to write. | |
116 | * @throws SaveException if anything goes wrong. | |
117 | * @throws InterruptedException if the thread is interrupted | |
118 | */ | |
119 | public void doSave(Project project, File file) | |
120 | throws SaveException, InterruptedException { | |
121 | ||
122 | /* Retain the previous project file even when the save operation | |
123 | * crashes in the middle. Also create a backup file after saving. */ | |
124 | boolean doSafeSaves = useSafeSaves(); | |
125 | ||
126 | ProgressMgr progressMgr = new ProgressMgr(); | |
127 |
1
1. doSave : removed call to org/argouml/persistence/AbstractFilePersister$ProgressMgr::setNumberOfPhases → NO_COVERAGE |
progressMgr.setNumberOfPhases(4); |
128 |
1
1. doSave : removed call to org/argouml/persistence/AbstractFilePersister$ProgressMgr::nextPhase → NO_COVERAGE |
progressMgr.nextPhase(); |
129 | ||
130 | File lastArchiveFile = new File(file.getAbsolutePath() + "~"); | |
131 | File tempFile = null; | |
132 | ||
133 |
1
1. doSave : negated conditional → NO_COVERAGE |
if (doSafeSaves) { |
134 | try { | |
135 | tempFile = createTempFile(file); | |
136 | } catch (FileNotFoundException e) { | |
137 | throw new SaveException(Translator.localize( | |
138 | "optionpane.save-project-exception-cause1"), e); | |
139 | } catch (IOException e) { | |
140 | throw new SaveException(Translator.localize( | |
141 | "optionpane.save-project-exception-cause2"), e); | |
142 | } | |
143 | } | |
144 | ||
145 | OutputStream stream = null; | |
146 | try { | |
147 | stream = new FileOutputStream(file); | |
148 |
1
1. doSave : removed call to org/argouml/persistence/XmiFilePersister::writeProject → NO_COVERAGE |
writeProject(project, stream, progressMgr); |
149 |
1
1. doSave : removed call to java/io/OutputStream::close → NO_COVERAGE |
stream.close(); |
150 | ||
151 |
1
1. doSave : negated conditional → NO_COVERAGE |
if (doSafeSaves) { |
152 | // if save did not raise an exception | |
153 | // and name+"#" exists move name+"#" to name+"~" | |
154 | // this is the correct backup file | |
155 |
1
1. doSave : negated conditional → NO_COVERAGE |
if (lastArchiveFile.exists()) { |
156 | lastArchiveFile.delete(); | |
157 | } | |
158 |
2
1. doSave : negated conditional → NO_COVERAGE 2. doSave : negated conditional → NO_COVERAGE |
if (tempFile.exists() && !lastArchiveFile.exists()) { |
159 | tempFile.renameTo(lastArchiveFile); | |
160 | } | |
161 |
1
1. doSave : negated conditional → NO_COVERAGE |
if (tempFile.exists()) { |
162 | tempFile.delete(); | |
163 | } | |
164 | } | |
165 | } catch (InterruptedException exc) { | |
166 | try { | |
167 |
1
1. doSave : removed call to java/io/OutputStream::close → NO_COVERAGE |
stream.close(); |
168 | } catch (IOException ex) { } | |
169 | throw exc; | |
170 | } catch (Exception e) { | |
171 | LOG.log(Level.SEVERE, "Exception occured during save attempt", e); | |
172 | try { | |
173 |
1
1. doSave : removed call to java/io/OutputStream::close → NO_COVERAGE |
stream.close(); |
174 | } catch (IOException ex) { } | |
175 | ||
176 |
1
1. doSave : negated conditional → NO_COVERAGE |
if (doSafeSaves) { |
177 | // frank: in case of exception | |
178 | // delete name and mv name+"#" back to name if name+"#" exists | |
179 | // this is the "rollback" to old file | |
180 | file.delete(); | |
181 | tempFile.renameTo(file); | |
182 | } | |
183 | // we have to give a message to user and set the system to unsaved! | |
184 | throw new SaveException(e); | |
185 | } | |
186 |
1
1. doSave : removed call to org/argouml/persistence/AbstractFilePersister$ProgressMgr::nextPhase → NO_COVERAGE |
progressMgr.nextPhase(); |
187 | } | |
188 | ||
189 | /** | |
190 | * Write the output for a project on the given stream. | |
191 | * | |
192 | * @param project The project to output. | |
193 | * @param stream The stream to write to. | |
194 | * @param progressMgr The progress manager/monitor, if any. If null, no | |
195 | * progress will be reported. | |
196 | * @throws SaveException If something goes wrong. | |
197 | * @throws InterruptedException if the thread is interrupted | |
198 | */ | |
199 | void writeProject(Project project, | |
200 | OutputStream stream, | |
201 | ProgressMgr progressMgr) throws SaveException, | |
202 | InterruptedException { | |
203 | ||
204 | int size = project.getMembers().size(); | |
205 |
3
1. writeProject : changed conditional boundary → NO_COVERAGE 2. writeProject : Changed increment from 1 to -1 → NO_COVERAGE 3. writeProject : negated conditional → NO_COVERAGE |
for (int i = 0; i < size; i++) { |
206 | ProjectMember projectMember = | |
207 | project.getMembers().get(i); | |
208 |
1
1. writeProject : negated conditional → NO_COVERAGE |
if (projectMember.getType().equalsIgnoreCase(getExtension())) { |
209 | if (LOG.isLoggable(Level.INFO)) { | |
210 | LOG.log(Level.INFO, "Saving member of type: {0}", | |
211 | projectMember.getType()); | |
212 | } | |
213 | MemberFilePersister persister = new ModelMemberFilePersister(); | |
214 |
1
1. writeProject : removed call to org/argouml/persistence/MemberFilePersister::save → NO_COVERAGE |
persister.save(projectMember, stream); |
215 | } | |
216 | } | |
217 | ||
218 |
1
1. writeProject : negated conditional → NO_COVERAGE |
if (progressMgr != null) { |
219 |
1
1. writeProject : removed call to org/argouml/persistence/AbstractFilePersister$ProgressMgr::nextPhase → NO_COVERAGE |
progressMgr.nextPhase(); |
220 | } | |
221 | ||
222 | } | |
223 | ||
224 | ||
225 | /** | |
226 | * This method creates a project from the specified URL | |
227 | * | |
228 | * Unlike the constructor which forces an .argo extension This | |
229 | * method will attempt to load a raw XMI file | |
230 | * | |
231 | * This method can fail in several different ways. Either by | |
232 | * throwing an exception or by having the | |
233 | * ArgoParser.SINGLETON.getLastLoadStatus() set to not true. | |
234 | * | |
235 | * @param file The file to load the project from. | |
236 | * @return The newly loaded project. | |
237 | * @throws OpenException if the file can not be opened | |
238 | * @throws InterruptedException if the thread is interrupted | |
239 | * | |
240 | * @see org.argouml.persistence.ProjectFilePersister#doLoad(java.io.File) | |
241 | */ | |
242 | public Project doLoad(File file) | |
243 | throws OpenException, InterruptedException { | |
244 | ||
245 | LOG.log(Level.INFO, "Loading with XMIFilePersister"); | |
246 | ||
247 | try { | |
248 | Project p = ProjectFactory.getInstance().createProject(); | |
249 | ||
250 | ||
251 | long length = file.length(); | |
252 | long phaseSpace = 100000; | |
253 |
1
1. doLoad : Replaced long division with multiplication → NO_COVERAGE |
int phases = (int) (length / phaseSpace); |
254 |
2
1. doLoad : changed conditional boundary → NO_COVERAGE 2. doLoad : negated conditional → NO_COVERAGE |
if (phases < 10) { |
255 |
1
1. doLoad : Replaced long division with multiplication → NO_COVERAGE |
phaseSpace = length / 10; |
256 | phases = 10; | |
257 | } | |
258 | LOG.log(Level.INFO, "File length is " + length + " phase space is " | |
259 | + phaseSpace + " phases is " + phases); | |
260 | ProgressMgr progressMgr = new ProgressMgr(); | |
261 |
1
1. doLoad : removed call to org/argouml/persistence/AbstractFilePersister$ProgressMgr::setNumberOfPhases → NO_COVERAGE |
progressMgr.setNumberOfPhases(phases); |
262 |
1
1. doLoad : removed call to org/argouml/util/ThreadUtils::checkIfInterrupted → NO_COVERAGE |
ThreadUtils.checkIfInterrupted(); |
263 | ||
264 | InputSource source = new InputSource(new XmiInputStream(file | |
265 | .toURI().toURL().openStream(), this, phaseSpace, | |
266 | progressMgr)); | |
267 |
1
1. doLoad : removed call to org/xml/sax/InputSource::setSystemId → NO_COVERAGE |
source.setSystemId(file.toURI().toURL().toString()); |
268 | ||
269 | ModelMemberFilePersister modelPersister = | |
270 | new ModelMemberFilePersister(); | |
271 | ||
272 |
1
1. doLoad : removed call to org/argouml/persistence/ModelMemberFilePersister::readModels → NO_COVERAGE |
modelPersister.readModels(source); |
273 | Object model = modelPersister.getCurModel(); | |
274 |
1
1. doLoad : removed call to org/argouml/persistence/AbstractFilePersister$ProgressMgr::nextPhase → NO_COVERAGE |
progressMgr.nextPhase(); |
275 |
1
1. doLoad : removed call to org/argouml/model/UmlHelper::addListenersToModel → NO_COVERAGE |
Model.getUmlHelper().addListenersToModel(model); |
276 |
1
1. doLoad : removed call to org/argouml/kernel/Project::setUUIDRefs → NO_COVERAGE |
p.setUUIDRefs(modelPersister.getUUIDRefs()); |
277 | // TODO Handle multiple top level packages | |
278 |
1
1. doLoad : removed call to org/argouml/kernel/Project::addMember → NO_COVERAGE |
p.addMember(model); |
279 |
1
1. doLoad : removed call to org/argouml/persistence/XmiFilePersister::parseXmiExtensions → NO_COVERAGE |
parseXmiExtensions(p); |
280 |
1
1. doLoad : removed call to org/argouml/persistence/ModelMemberFilePersister::registerDiagrams → NO_COVERAGE |
modelPersister.registerDiagrams(p); |
281 | ||
282 |
1
1. doLoad : removed call to org/argouml/kernel/Project::setRoot → NO_COVERAGE |
p.setRoot(model); |
283 |
1
1. doLoad : removed call to org/argouml/kernel/Project::setRoots → NO_COVERAGE |
p.setRoots(modelPersister.getElementsRead()); |
284 |
1
1. doLoad : removed call to org/argouml/kernel/Project::updateRoots → NO_COVERAGE |
p.updateRoots(); |
285 | File defaultProjectFile = new File(file.getPath() + ".zargo"); | |
286 | // Make sure the file doesn't exist so the user will | |
287 | // get prompted to choose a new name | |
288 |
3
1. doLoad : changed conditional boundary → NO_COVERAGE 2. doLoad : Changed increment from 1 to -1 → NO_COVERAGE 3. doLoad : negated conditional → NO_COVERAGE |
for (int i = 0; i < 99; i++) { |
289 |
1
1. doLoad : negated conditional → NO_COVERAGE |
if (!defaultProjectFile.exists()) { |
290 | break; | |
291 | } | |
292 | defaultProjectFile = | |
293 | new File(file.getPath() + "." + i + ".zargo"); | |
294 | } | |
295 |
1
1. doLoad : removed call to org/argouml/persistence/PersistenceManager::setProjectURI → NO_COVERAGE |
PersistenceManager.getInstance().setProjectURI( |
296 | defaultProjectFile.toURI(), p); | |
297 |
1
1. doLoad : removed call to org/argouml/persistence/AbstractFilePersister$ProgressMgr::nextPhase → NO_COVERAGE |
progressMgr.nextPhase(); |
298 |
1
1. doLoad : removed call to org/argouml/kernel/ProjectManager::setSaveEnabled → NO_COVERAGE |
ProjectManager.getManager().setSaveEnabled(false); |
299 |
1
1. doLoad : mutated return of Object value for org/argouml/persistence/XmiFilePersister::doLoad to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return p; |
300 | } catch (IOException e) { | |
301 | throw new OpenException(e); | |
302 | } | |
303 | } | |
304 | ||
305 | /** | |
306 | * Returns true. All Argo specific files have an icon. | |
307 | * | |
308 | * @see org.argouml.persistence.AbstractFilePersister#hasAnIcon() | |
309 | */ | |
310 | public boolean hasAnIcon() { | |
311 |
1
1. hasAnIcon : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE |
return true; |
312 | } | |
313 | ||
314 | /** | |
315 | * Parse a string of XML that is the XMI.extension contents. | |
316 | * This implementation simply stores the xml strings to process | |
317 | * in one hit after all the standard XMI has been read. | |
318 | * @see org.argouml.persistence.XmiExtensionParser#parse(java.lang.String, java.lang.String) | |
319 | */ | |
320 | public void parse(String label, String xmiExtensionString) { | |
321 |
1
1. parse : negated conditional → NO_COVERAGE |
if (label.equals("pgml")) { |
322 | pgmlStrings.add(xmiExtensionString); | |
323 |
1
1. parse : negated conditional → NO_COVERAGE |
} else if (label.equals("argo")) { |
324 | argoString = xmiExtensionString; | |
325 |
1
1. parse : negated conditional → NO_COVERAGE |
} else if (label.equals("todo")) { |
326 | todoString = xmiExtensionString; | |
327 | } | |
328 | } | |
329 | ||
330 | /** | |
331 | * Parse all the extensions that were found when reading XMI | |
332 | * | |
333 | * @param project | |
334 | * @exception OpenException | |
335 | */ | |
336 | public void parseXmiExtensions(Project project) throws OpenException { | |
337 | ||
338 |
1
1. parseXmiExtensions : negated conditional → NO_COVERAGE |
if (argoString != null) { |
339 | LOG.log(Level.INFO, "Parsing argoString {0}", argoString.length()); | |
340 | ||
341 | StringReader inputStream = new StringReader(argoString); | |
342 | ArgoParser parser = new ArgoParser(); | |
343 | try { | |
344 |
1
1. parseXmiExtensions : removed call to org/argouml/persistence/ArgoParser::readProject → NO_COVERAGE |
parser.readProject(project, inputStream); |
345 | } catch (Exception e) { | |
346 | throw new OpenException("Exception caught", e); | |
347 | } | |
348 | } else { | |
349 |
1
1. parseXmiExtensions : removed call to org/argouml/kernel/Project::addMember → NO_COVERAGE |
project.addMember(new ProjectMemberTodoList("", project)); |
350 | } | |
351 |
1
1. parseXmiExtensions : negated conditional → NO_COVERAGE |
for (String pgml : pgmlStrings) { |
352 | LOG.log(Level.INFO, "Parsing pgml {0}", pgml.length()); | |
353 | ||
354 | InputStream inputStream = new ByteArrayInputStream(pgml.getBytes()); | |
355 | MemberFilePersister persister = | |
356 | // TODO: Cyclic dependency between PersistanceManager and here | |
357 | PersistenceManager.getInstance() | |
358 | .getDiagramMemberFilePersister(); | |
359 | // possibly use the following instead | |
360 | // MemberFilePersister persister = new DiagramMemberFilePersister(); | |
361 |
1
1. parseXmiExtensions : removed call to org/argouml/persistence/MemberFilePersister::load → NO_COVERAGE |
persister.load(project, inputStream); |
362 | } | |
363 |
1
1. parseXmiExtensions : negated conditional → NO_COVERAGE |
if (todoString != null) { |
364 | LOG.log(Level.INFO, "Parsing todoString {0}", todoString.length()); | |
365 | ||
366 | InputStream inputStream = | |
367 | new ByteArrayInputStream(todoString.getBytes()); | |
368 | MemberFilePersister persister = null; | |
369 | persister = new TodoListMemberFilePersister(); | |
370 |
1
1. parseXmiExtensions : removed call to org/argouml/persistence/MemberFilePersister::load → NO_COVERAGE |
persister.load(project, inputStream); |
371 | } else { | |
372 |
1
1. parseXmiExtensions : removed call to org/argouml/kernel/Project::addMember → NO_COVERAGE |
project.addMember(new ProjectMemberTodoList("", project)); |
373 | } | |
374 | } | |
375 | } | |
Mutations | ||
94 |
1.1 |
|
101 |
1.1 |
|
108 |
1.1 |
|
127 |
1.1 |
|
128 |
1.1 |
|
133 |
1.1 |
|
148 |
1.1 |
|
149 |
1.1 |
|
151 |
1.1 |
|
155 |
1.1 |
|
158 |
1.1 2.2 |
|
161 |
1.1 |
|
167 |
1.1 |
|
173 |
1.1 |
|
176 |
1.1 |
|
186 |
1.1 |
|
205 |
1.1 2.2 3.3 |
|
208 |
1.1 |
|
214 |
1.1 |
|
218 |
1.1 |
|
219 |
1.1 |
|
253 |
1.1 |
|
254 |
1.1 2.2 |
|
255 |
1.1 |
|
261 |
1.1 |
|
262 |
1.1 |
|
267 |
1.1 |
|
272 |
1.1 |
|
274 |
1.1 |
|
275 |
1.1 |
|
276 |
1.1 |
|
278 |
1.1 |
|
279 |
1.1 |
|
280 |
1.1 |
|
282 |
1.1 |
|
283 |
1.1 |
|
284 |
1.1 |
|
288 |
1.1 2.2 3.3 |
|
289 |
1.1 |
|
295 |
1.1 |
|
297 |
1.1 |
|
298 |
1.1 |
|
299 |
1.1 |
|
311 |
1.1 |
|
321 |
1.1 |
|
323 |
1.1 |
|
325 |
1.1 |
|
338 |
1.1 |
|
344 |
1.1 |
|
349 |
1.1 |
|
351 |
1.1 |
|
361 |
1.1 |
|
363 |
1.1 |
|
370 |
1.1 |
|
372 |
1.1 |