1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
|
23 | |
|
24 | |
|
25 | |
|
26 | |
|
27 | |
|
28 | |
|
29 | |
|
30 | |
|
31 | |
|
32 | |
|
33 | |
|
34 | |
|
35 | |
|
36 | |
|
37 | |
|
38 | |
|
39 | |
package org.argouml.persistence; |
40 | |
|
41 | |
import java.io.BufferedReader; |
42 | |
import java.io.BufferedWriter; |
43 | |
import java.io.File; |
44 | |
import java.io.FileNotFoundException; |
45 | |
import java.io.FileOutputStream; |
46 | |
import java.io.FilterInputStream; |
47 | |
import java.io.IOException; |
48 | |
import java.io.InputStream; |
49 | |
import java.io.InputStreamReader; |
50 | |
import java.io.OutputStreamWriter; |
51 | |
import java.io.PrintWriter; |
52 | |
import java.io.Reader; |
53 | |
import java.io.UnsupportedEncodingException; |
54 | |
import java.io.Writer; |
55 | |
import java.net.MalformedURLException; |
56 | |
import java.net.URL; |
57 | |
import java.util.ArrayList; |
58 | |
import java.util.List; |
59 | |
import java.util.zip.ZipEntry; |
60 | |
import java.util.zip.ZipInputStream; |
61 | |
import java.util.zip.ZipOutputStream; |
62 | |
|
63 | |
import org.apache.log4j.Logger; |
64 | |
import org.argouml.application.api.Argo; |
65 | |
import org.argouml.application.helpers.ApplicationVersion; |
66 | |
import org.argouml.i18n.Translator; |
67 | |
import org.argouml.kernel.ProfileConfiguration; |
68 | |
import org.argouml.kernel.Project; |
69 | |
import org.argouml.kernel.ProjectFactory; |
70 | |
import org.argouml.kernel.ProjectMember; |
71 | |
import org.argouml.model.Model; |
72 | |
import org.argouml.util.FileConstants; |
73 | |
import org.argouml.util.ThreadUtils; |
74 | |
import org.xml.sax.InputSource; |
75 | |
import org.xml.sax.SAXException; |
76 | |
|
77 | |
|
78 | |
|
79 | |
|
80 | |
|
81 | |
|
82 | |
class ZargoFilePersister extends UmlFilePersister { |
83 | |
|
84 | |
|
85 | |
|
86 | 900 | private static final Logger LOG = |
87 | |
Logger.getLogger(ZargoFilePersister.class); |
88 | |
|
89 | |
|
90 | |
|
91 | |
|
92 | 900 | public ZargoFilePersister() { |
93 | 900 | } |
94 | |
|
95 | |
|
96 | |
|
97 | |
|
98 | |
@Override |
99 | |
public String getExtension() { |
100 | 10000 | return "zargo"; |
101 | |
} |
102 | |
|
103 | |
|
104 | |
|
105 | |
|
106 | |
@Override |
107 | |
protected String getDesc() { |
108 | 0 | return Translator.localize("combobox.filefilter.zargo"); |
109 | |
} |
110 | |
|
111 | |
|
112 | |
|
113 | |
|
114 | |
|
115 | |
|
116 | |
|
117 | |
|
118 | |
|
119 | |
|
120 | |
|
121 | |
|
122 | |
|
123 | |
|
124 | |
|
125 | |
|
126 | |
@Override |
127 | |
public void doSave(Project project, File file) throws SaveException, |
128 | |
InterruptedException { |
129 | |
|
130 | 0 | LOG.info("Saving"); |
131 | 0 | ProgressMgr progressMgr = new ProgressMgr(); |
132 | 0 | progressMgr.setNumberOfPhases(4); |
133 | 0 | progressMgr.nextPhase(); |
134 | |
|
135 | 0 | File lastArchiveFile = new File(file.getAbsolutePath() + "~"); |
136 | 0 | File tempFile = null; |
137 | |
|
138 | |
try { |
139 | 0 | tempFile = createTempFile(file); |
140 | 0 | } catch (FileNotFoundException e) { |
141 | 0 | throw new SaveException( |
142 | |
"Failed to archive the previous file version", e); |
143 | 0 | } catch (IOException e) { |
144 | 0 | throw new SaveException( |
145 | |
"Failed to archive the previous file version", e); |
146 | 0 | } |
147 | |
|
148 | 0 | ZipOutputStream stream = null; |
149 | |
try { |
150 | |
|
151 | 0 | project.setFile(file); |
152 | 0 | project.setVersion(ApplicationVersion.getVersion()); |
153 | 0 | project.setPersistenceVersion(PERSISTENCE_VERSION); |
154 | |
|
155 | 0 | stream = new ZipOutputStream(new FileOutputStream(file)); |
156 | |
|
157 | 0 | for (ProjectMember projectMember : project.getMembers()) { |
158 | 0 | if (projectMember.getType().equalsIgnoreCase("xmi")) { |
159 | 0 | if (LOG.isInfoEnabled()) { |
160 | 0 | LOG.info("Saving member of type: " |
161 | |
+ projectMember.getType()); |
162 | |
} |
163 | 0 | stream.putNextEntry( |
164 | |
new ZipEntry(projectMember.getZipName())); |
165 | 0 | MemberFilePersister persister = |
166 | |
getMemberFilePersister(projectMember); |
167 | 0 | persister.save(projectMember, stream); |
168 | 0 | } |
169 | |
} |
170 | |
|
171 | |
|
172 | |
|
173 | 0 | if (lastArchiveFile.exists()) { |
174 | 0 | lastArchiveFile.delete(); |
175 | |
} |
176 | 0 | if (tempFile.exists() && !lastArchiveFile.exists()) { |
177 | 0 | tempFile.renameTo(lastArchiveFile); |
178 | |
} |
179 | 0 | if (tempFile.exists()) { |
180 | 0 | tempFile.delete(); |
181 | |
} |
182 | |
|
183 | 0 | progressMgr.nextPhase(); |
184 | |
|
185 | 0 | } catch (Exception e) { |
186 | 0 | LOG.error("Exception occured during save attempt", e); |
187 | |
try { |
188 | 0 | if (stream != null) { |
189 | 0 | stream.close(); |
190 | |
} |
191 | 0 | } catch (Exception ex) { |
192 | |
|
193 | 0 | } |
194 | |
|
195 | |
|
196 | |
|
197 | |
|
198 | 0 | file.delete(); |
199 | 0 | tempFile.renameTo(file); |
200 | |
|
201 | 0 | throw new SaveException(e); |
202 | 0 | } |
203 | |
|
204 | |
try { |
205 | 0 | stream.close(); |
206 | 0 | } catch (IOException ex) { |
207 | 0 | LOG.error("Failed to close save output writer", ex); |
208 | 0 | } |
209 | 0 | } |
210 | |
|
211 | |
|
212 | |
|
213 | |
|
214 | |
@Override |
215 | |
public boolean isSaveEnabled() { |
216 | 0 | return false; |
217 | |
} |
218 | |
|
219 | |
|
220 | |
|
221 | |
|
222 | |
@Override |
223 | |
public Project doLoad(File file) |
224 | |
throws OpenException, InterruptedException { |
225 | |
|
226 | 0 | ProgressMgr progressMgr = new ProgressMgr(); |
227 | 0 | progressMgr.setNumberOfPhases(3 + UML_PHASES_LOAD); |
228 | 0 | ThreadUtils.checkIfInterrupted(); |
229 | |
|
230 | |
int fileVersion; |
231 | |
String releaseVersion; |
232 | |
try { |
233 | 0 | String argoEntry = getEntryNames(file, ".argo").iterator().next(); |
234 | 0 | URL argoUrl = makeZipEntryUrl(toURL(file), argoEntry); |
235 | 0 | fileVersion = getPersistenceVersion(argoUrl.openStream()); |
236 | 0 | releaseVersion = getReleaseVersion(argoUrl.openStream()); |
237 | 0 | } catch (MalformedURLException e) { |
238 | 0 | throw new OpenException(e); |
239 | 0 | } catch (IOException e) { |
240 | 0 | throw new OpenException(e); |
241 | 0 | } |
242 | |
|
243 | |
|
244 | |
|
245 | |
|
246 | |
|
247 | |
|
248 | 0 | boolean upgradeRequired = true; |
249 | |
|
250 | |
|
251 | 0 | if (Model.getFacade().getUmlVersion().charAt(0) == '2') { |
252 | 0 | upgradeRequired = false; |
253 | |
} |
254 | |
|
255 | 0 | LOG.info("Loading zargo file of version " + fileVersion); |
256 | |
|
257 | |
final Project p; |
258 | 0 | if (upgradeRequired) { |
259 | 0 | File combinedFile = zargoToUml(file, progressMgr); |
260 | 0 | p = super.doLoad(file, combinedFile, progressMgr); |
261 | 0 | } else { |
262 | 0 | p = loadFromZargo(file, progressMgr); |
263 | |
} |
264 | |
|
265 | 0 | progressMgr.nextPhase(); |
266 | |
|
267 | 0 | PersistenceManager.getInstance().setProjectURI(file.toURI(), p); |
268 | 0 | return p; |
269 | |
|
270 | |
} |
271 | |
|
272 | |
private Project loadFromZargo(File file, ProgressMgr progressMgr) |
273 | |
throws OpenException { |
274 | |
|
275 | 0 | Project p = ProjectFactory.getInstance().createProject(file.toURI()); |
276 | |
try { |
277 | 0 | progressMgr.nextPhase(); |
278 | |
|
279 | |
|
280 | 0 | ArgoParser parser = new ArgoParser(); |
281 | 0 | String argoEntry = getEntryNames(file, ".argo").iterator().next(); |
282 | 0 | parser.readProject(p, new InputSource(makeZipEntryUrl(toURL(file), |
283 | |
argoEntry).toExternalForm())); |
284 | |
|
285 | 0 | List memberList = parser.getMemberList(); |
286 | |
|
287 | 0 | LOG.info(memberList.size() + " members"); |
288 | |
|
289 | |
|
290 | |
|
291 | |
|
292 | |
|
293 | |
|
294 | 0 | String xmiEntry = getEntryNames(file, ".xmi").iterator().next(); |
295 | 0 | MemberFilePersister persister = getMemberFilePersister("xmi"); |
296 | 0 | URL url = makeZipEntryUrl(toURL(file), xmiEntry); |
297 | 0 | persister.load(p, new InputSource(url.toExternalForm())); |
298 | |
|
299 | |
|
300 | 0 | List<String> entries = getEntryNames(file, null); |
301 | 0 | for (String name : entries) { |
302 | 0 | String ext = name.substring(name.lastIndexOf('.') + 1); |
303 | 0 | if (!"argo".equals(ext) && !"xmi".equals(ext)) { |
304 | 0 | persister = getMemberFilePersister(ext); |
305 | 0 | LOG.info("Loading member with " |
306 | |
+ persister.getClass().getName()); |
307 | 0 | url = makeZipEntryUrl(toURL(file), name); |
308 | 0 | persister.load(p, new InputSource(url.toExternalForm())); |
309 | |
} |
310 | 0 | } |
311 | |
|
312 | 0 | progressMgr.nextPhase(); |
313 | 0 | ThreadUtils.checkIfInterrupted(); |
314 | 0 | p.postLoad(); |
315 | 0 | return p; |
316 | 0 | } catch (InterruptedException e) { |
317 | 0 | return null; |
318 | 0 | } catch (MalformedURLException e) { |
319 | 0 | throw new OpenException(e); |
320 | 0 | } catch (IOException e) { |
321 | 0 | throw new OpenException(e); |
322 | 0 | } catch (SAXException e) { |
323 | 0 | throw new OpenException(e); |
324 | |
} |
325 | |
} |
326 | |
|
327 | |
private URL toURL(File file) throws MalformedURLException { |
328 | 0 | return file.toURI().toURL(); |
329 | |
} |
330 | |
|
331 | |
|
332 | |
private File zargoToUml(File file, ProgressMgr progressMgr) |
333 | |
throws OpenException, InterruptedException { |
334 | |
|
335 | 0 | File combinedFile = null; |
336 | |
try { |
337 | 0 | combinedFile = File.createTempFile("combinedzargo_", ".uml"); |
338 | 0 | LOG.info( |
339 | |
"Combining old style zargo sub files into new style uml file " |
340 | |
+ combinedFile.getAbsolutePath()); |
341 | 0 | combinedFile.deleteOnExit(); |
342 | |
|
343 | 0 | String encoding = Argo.getEncoding(); |
344 | 0 | FileOutputStream stream = new FileOutputStream(combinedFile); |
345 | 0 | PrintWriter writer = |
346 | |
new PrintWriter(new BufferedWriter( |
347 | |
new OutputStreamWriter(stream, encoding))); |
348 | |
|
349 | 0 | writer.println("<?xml version = \"1.0\" " + "encoding = \"" |
350 | |
+ encoding + "\" ?>"); |
351 | |
|
352 | 0 | copyArgo(file, encoding, writer); |
353 | |
|
354 | 0 | progressMgr.nextPhase(); |
355 | |
|
356 | 0 | copyMember(file, "profile", encoding, writer); |
357 | |
|
358 | 0 | copyXmi(file, encoding, writer); |
359 | |
|
360 | 0 | copyDiagrams(file, encoding, writer); |
361 | |
|
362 | |
|
363 | |
|
364 | |
|
365 | 0 | copyMember(file, "todo", encoding, writer); |
366 | |
|
367 | 0 | progressMgr.nextPhase(); |
368 | |
|
369 | 0 | writer.println("</uml>"); |
370 | 0 | writer.close(); |
371 | 0 | LOG.info("Completed combining files"); |
372 | 0 | } catch (IOException e) { |
373 | 0 | throw new OpenException(e); |
374 | 0 | } |
375 | 0 | return combinedFile; |
376 | |
} |
377 | |
|
378 | |
|
379 | |
private void copyArgo(File file, String encoding, PrintWriter writer) |
380 | |
throws IOException, MalformedURLException, OpenException, |
381 | |
UnsupportedEncodingException { |
382 | |
|
383 | 0 | int pgmlCount = getPgmlCount(file); |
384 | 0 | boolean containsToDo = containsTodo(file); |
385 | 0 | boolean containsProfile = containsProfile(file); |
386 | |
|
387 | |
|
388 | 0 | ZipInputStream zis = |
389 | |
openZipStreamAt(toURL(file), FileConstants.PROJECT_FILE_EXT); |
390 | |
|
391 | 0 | if (zis == null) { |
392 | 0 | throw new OpenException( |
393 | |
"There is no .argo file in the .zargo"); |
394 | |
} |
395 | |
|
396 | |
String line; |
397 | 0 | BufferedReader reader = |
398 | |
new BufferedReader(new InputStreamReader(zis, encoding)); |
399 | |
|
400 | |
String rootLine; |
401 | |
do { |
402 | 0 | rootLine = reader.readLine(); |
403 | 0 | if (rootLine == null) { |
404 | 0 | throw new OpenException( |
405 | |
"Can't find an <argo> tag in the argo file"); |
406 | |
} |
407 | 0 | } while(!rootLine.startsWith("<argo")); |
408 | |
|
409 | |
|
410 | |
|
411 | 0 | String version = getVersion(rootLine); |
412 | 0 | writer.println("<uml version=\"" + version + "\">"); |
413 | 0 | writer.println(rootLine); |
414 | 0 | LOG.info("Transfering argo contents"); |
415 | 0 | int memberCount = 0; |
416 | 0 | while ((line = reader.readLine()) != null) { |
417 | 0 | if (line.trim().startsWith("<member")) { |
418 | 0 | ++memberCount; |
419 | |
} |
420 | 0 | if (line.trim().equals("</argo>") && memberCount == 0) { |
421 | 0 | LOG.info("Inserting member info"); |
422 | 0 | writer.println("<member type='xmi' name='.xmi' />"); |
423 | 0 | for (int i = 0; i < pgmlCount; ++i) { |
424 | 0 | writer.println("<member type='pgml' name='.pgml' />"); |
425 | |
} |
426 | 0 | if (containsToDo) { |
427 | 0 | writer.println("<member type='todo' name='.todo' />"); |
428 | |
} |
429 | 0 | if (containsProfile) { |
430 | 0 | String type = ProfileConfiguration.EXTENSION; |
431 | 0 | writer.println("<member type='" + type + "' name='." |
432 | |
+ type + "' />"); |
433 | |
} |
434 | |
} |
435 | 0 | writer.println(line); |
436 | |
} |
437 | 0 | if (LOG.isInfoEnabled()) { |
438 | 0 | LOG.info("Member count = " + memberCount); |
439 | |
} |
440 | 0 | zis.close(); |
441 | 0 | reader.close(); |
442 | 0 | } |
443 | |
|
444 | |
private void copyXmi(File file, String encoding, PrintWriter writer) |
445 | |
throws IOException, MalformedURLException, |
446 | |
UnsupportedEncodingException { |
447 | |
|
448 | 0 | ZipInputStream zis = openZipStreamAt(toURL(file), ".xmi"); |
449 | 0 | BufferedReader reader = new BufferedReader( |
450 | |
new InputStreamReader(zis, encoding)); |
451 | |
|
452 | 0 | reader.readLine(); |
453 | |
|
454 | 0 | readerToWriter(reader, writer); |
455 | |
|
456 | 0 | zis.close(); |
457 | 0 | reader.close(); |
458 | 0 | } |
459 | |
|
460 | |
|
461 | |
private void copyDiagrams(File file, String encoding, PrintWriter writer) |
462 | |
throws IOException { |
463 | |
|
464 | |
|
465 | 0 | ZipInputStream zis = new ZipInputStream(toURL(file).openStream()); |
466 | 0 | SubInputStream sub = new SubInputStream(zis); |
467 | |
|
468 | 0 | ZipEntry currentEntry = null; |
469 | 0 | while ((currentEntry = sub.getNextEntry()) != null) { |
470 | 0 | if (currentEntry.getName().endsWith(".pgml")) { |
471 | |
|
472 | 0 | BufferedReader reader = new BufferedReader( |
473 | |
new InputStreamReader(sub, encoding)); |
474 | 0 | String firstLine = reader.readLine(); |
475 | 0 | if (firstLine.startsWith("<?xml")) { |
476 | |
|
477 | |
|
478 | |
|
479 | 0 | reader.readLine(); |
480 | |
} else { |
481 | 0 | writer.println(firstLine); |
482 | |
} |
483 | |
|
484 | 0 | readerToWriter(reader, writer); |
485 | 0 | sub.close(); |
486 | 0 | reader.close(); |
487 | 0 | } |
488 | |
} |
489 | 0 | zis.close(); |
490 | 0 | } |
491 | |
|
492 | |
|
493 | |
private void copyMember(File file, String tag, String outputEncoding, |
494 | |
PrintWriter writer) throws IOException, MalformedURLException, |
495 | |
UnsupportedEncodingException { |
496 | |
|
497 | 0 | ZipInputStream zis = openZipStreamAt(toURL(file), "." + tag); |
498 | |
|
499 | 0 | if (zis != null) { |
500 | 0 | InputStreamReader isr = new InputStreamReader(zis, outputEncoding); |
501 | 0 | BufferedReader reader = new BufferedReader(isr); |
502 | |
|
503 | 0 | String firstLine = reader.readLine(); |
504 | 0 | if (firstLine.startsWith("<?xml")) { |
505 | |
|
506 | |
|
507 | |
|
508 | 0 | reader.readLine(); |
509 | |
} else { |
510 | 0 | writer.println(firstLine); |
511 | |
} |
512 | |
|
513 | 0 | readerToWriter(reader, writer); |
514 | |
|
515 | 0 | zis.close(); |
516 | 0 | reader.close(); |
517 | |
} |
518 | 0 | } |
519 | |
|
520 | |
|
521 | |
private void readerToWriter( |
522 | |
Reader reader, |
523 | |
Writer writer) throws IOException { |
524 | |
|
525 | |
int ch; |
526 | 0 | while ((ch = reader.read()) != -1) { |
527 | 0 | if (ch == 0xFFFF) { |
528 | 0 | LOG.info("Stripping out 0xFFFF from save file"); |
529 | 0 | } else if (ch == 8) { |
530 | 0 | LOG.info("Stripping out 0x8 from save file"); |
531 | |
} else { |
532 | 0 | writer.write(ch); |
533 | |
} |
534 | |
} |
535 | 0 | } |
536 | |
|
537 | |
|
538 | |
|
539 | |
|
540 | |
|
541 | |
|
542 | |
|
543 | |
|
544 | |
|
545 | |
|
546 | |
|
547 | |
|
548 | |
|
549 | |
private ZipInputStream openZipStreamAt(URL url, String ext) |
550 | |
throws IOException { |
551 | 0 | ZipInputStream zis = new ZipInputStream(url.openStream()); |
552 | 0 | ZipEntry entry = zis.getNextEntry(); |
553 | 0 | while (entry != null && !entry.getName().endsWith(ext)) { |
554 | 0 | entry = zis.getNextEntry(); |
555 | |
} |
556 | 0 | if (entry == null) { |
557 | 0 | zis.close(); |
558 | 0 | return null; |
559 | |
} |
560 | 0 | return zis; |
561 | |
} |
562 | |
|
563 | |
private InputStream openZipEntry(URL url, String entryName) |
564 | |
throws MalformedURLException, IOException { |
565 | 0 | return makeZipEntryUrl(url, entryName).openStream(); |
566 | |
} |
567 | |
|
568 | |
private URL makeZipEntryUrl(URL url, String entryName) |
569 | |
throws MalformedURLException { |
570 | 0 | String entryURL = "jar:" + url + "!/" + entryName; |
571 | 0 | return new URL(entryURL); |
572 | |
} |
573 | |
|
574 | |
|
575 | |
|
576 | |
|
577 | |
private static class SubInputStream extends FilterInputStream { |
578 | |
private ZipInputStream in; |
579 | |
|
580 | |
|
581 | |
|
582 | |
|
583 | |
|
584 | |
|
585 | |
|
586 | |
public SubInputStream(ZipInputStream z) { |
587 | 0 | super(z); |
588 | 0 | in = z; |
589 | 0 | } |
590 | |
|
591 | |
|
592 | |
|
593 | |
|
594 | |
@Override |
595 | |
public void close() throws IOException { |
596 | 0 | in.closeEntry(); |
597 | 0 | } |
598 | |
|
599 | |
|
600 | |
|
601 | |
|
602 | |
|
603 | |
|
604 | |
|
605 | |
|
606 | |
|
607 | |
public ZipEntry getNextEntry() throws IOException { |
608 | 0 | return in.getNextEntry(); |
609 | |
} |
610 | |
} |
611 | |
|
612 | |
private int getPgmlCount(File file) throws IOException { |
613 | 0 | return getEntryNames(file, ".pgml").size(); |
614 | |
} |
615 | |
|
616 | |
private boolean containsTodo(File file) throws IOException { |
617 | 0 | return !getEntryNames(file, ".todo").isEmpty(); |
618 | |
} |
619 | |
|
620 | |
private boolean containsProfile(File file) throws IOException { |
621 | 0 | return !getEntryNames(file, "." + ProfileConfiguration.EXTENSION) |
622 | |
.isEmpty(); |
623 | |
} |
624 | |
|
625 | |
|
626 | |
|
627 | |
|
628 | |
|
629 | |
private List<String> getEntryNames(File file, String extension) |
630 | |
throws IOException, MalformedURLException { |
631 | |
|
632 | 0 | ZipInputStream zis = new ZipInputStream(toURL(file).openStream()); |
633 | 0 | List<String> result = new ArrayList<String>(); |
634 | 0 | ZipEntry entry = zis.getNextEntry(); |
635 | 0 | while (entry != null) { |
636 | 0 | String name = entry.getName(); |
637 | 0 | if (extension == null || name.endsWith(extension)) { |
638 | 0 | result.add(name); |
639 | |
} |
640 | 0 | entry = zis.getNextEntry(); |
641 | 0 | } |
642 | 0 | zis.close(); |
643 | 0 | return result; |
644 | |
} |
645 | |
|
646 | |
|
647 | |
} |