Coverage Report - org.argouml.persistence.ZargoFilePersister
 
Classes in this File Line Coverage Branch Coverage Complexity
ZargoFilePersister
1%
4/234
0%
0/80
3.667
ZargoFilePersister$SubInputStream
0%
0/6
N/A
3.667
 
 1  
 /* $Id: ZargoFilePersister.java 17959 2010-02-04 12:45:05Z thn $
 2  
  *****************************************************************************
 3  
  * Copyright (c) 2009 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  
  *****************************************************************************
 12  
  *
 13  
  * Some portions of this file was previously release using the BSD License:
 14  
  */
 15  
 
 16  
 // Copyright (c) 1996-2008 The Regents of the University of California. All
 17  
 // Rights Reserved. Permission to use, copy, modify, and distribute this
 18  
 // software and its documentation without fee, and without a written
 19  
 // agreement is hereby granted, provided that the above copyright notice
 20  
 // and this paragraph appear in all copies.  This software program and
 21  
 // documentation are copyrighted by The Regents of the University of
 22  
 // California. The software program and documentation are supplied "AS
 23  
 // IS", without any accompanying services from The Regents. The Regents
 24  
 // does not warrant that the operation of the program will be
 25  
 // uninterrupted or error-free. The end-user understands that the program
 26  
 // was developed for research purposes and is advised not to rely
 27  
 // exclusively on the program for any reason.  IN NO EVENT SHALL THE
 28  
 // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 29  
 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
 30  
 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 31  
 // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 32  
 // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
 33  
 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 34  
 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 35  
 // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 36  
 // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 37  
 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 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  
  * To persist to and from zargo (zipped file) storage.
 79  
  *
 80  
  * @author Bob Tarling
 81  
  */
 82  
 class ZargoFilePersister extends UmlFilePersister {
 83  
     /**
 84  
      * Logger.
 85  
      */
 86  900
     private static final Logger LOG =
 87  
         Logger.getLogger(ZargoFilePersister.class);
 88  
 
 89  
     /**
 90  
      * The constructor.
 91  
      */
 92  900
     public ZargoFilePersister() {
 93  900
     }
 94  
 
 95  
     /*
 96  
      * @see org.argouml.persistence.AbstractFilePersister#getExtension()
 97  
      */
 98  
     @Override
 99  
     public String getExtension() {
 100  10000
         return "zargo";
 101  
     }
 102  
 
 103  
     /*
 104  
      * @see org.argouml.persistence.AbstractFilePersister#getDesc()
 105  
      */
 106  
     @Override
 107  
     protected String getDesc() {
 108  0
         return Translator.localize("combobox.filefilter.zargo");
 109  
     }
 110  
 
 111  
     /**
 112  
      * It is being considered to save out individual xmi's from individuals
 113  
      * diagrams to make it easier to modularize the output of Argo.
 114  
      *
 115  
      * @param file
 116  
      *            The file to write.
 117  
      * @param project
 118  
      *            the project to save
 119  
      * @throws SaveException
 120  
      *             when anything goes wrong
 121  
      * @throws InterruptedException     if the thread is interrupted
 122  
      *
 123  
      * @see org.argouml.persistence.ProjectFilePersister#save(
 124  
      *      org.argouml.kernel.Project, java.io.File)
 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  
             // if save did not raise an exception
 171  
             // and name+"#" exists move name+"#" to name+"~"
 172  
             // this is the correct backup file
 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  
                 // Do nothing.
 193  0
             }
 194  
 
 195  
             // frank: in case of exception
 196  
             // delete name and mv name+"#" back to name if name+"#" exists
 197  
             // this is the "rollback" to old file
 198  0
             file.delete();
 199  0
             tempFile.renameTo(file);
 200  
             // we have to give a message to user and set the system to unsaved!
 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  
      * @see org.argouml.persistence.AbstractFilePersister#isSaveEnabled()
 213  
      */
 214  
     @Override
 215  
     public boolean isSaveEnabled() {
 216  0
         return false;
 217  
     }
 218  
 
 219  
     /*
 220  
      * @see org.argouml.persistence.ProjectFilePersister#doLoad(java.io.File)
 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  
         // TODO: The commented code below was commented out by Bob Tarling
 244  
         // in order to resolve bugs 4845 and 4857. Hopefully we can
 245  
         // determine the cause and reintroduce.
 246  
         
 247  
         //boolean upgradeRequired = !checkVersion(fileVersion, releaseVersion)
 248  0
         boolean upgradeRequired = true;
 249  
         
 250  
         // Upgrade is in the way for UML2 projects, so we turn it off in that case:
 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  
             // Load .argo project descriptor
 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  
             // Load .xmi file before any PGML files
 290  
             // FIXME: the following is loading the model before anything else.
 291  
             // Due to the Zargo containing the profiles, currently we have 
 292  
             // removed this hack in UmlFilePersister and I think it should be 
 293  
             // removed from here also.
 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  
             // Load the rest
 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  
             // Copy the todo items after the model and diagrams so that
 363  
             // any model elements or figs that the todo items refer to
 364  
             // will exist before creating critics.
 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  
         // first read the .argo file from Zip
 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  
         // Keep reading till we hit the <argo> tag
 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  
         // Get the version from the tag.
 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  
         // Skip 1 lines
 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  
         // Loop round loading the diagrams
 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  
                     // Skip the 2 lines
 477  
                     //<?xml version="1.0" encoding="UTF-8" ?>
 478  
                     //<!DOCTYPE pgml SYSTEM "pgml.dtd">
 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  
                 // Skip the 2 lines
 506  
                 //<?xml version="1.0" encoding="UTF-8" ?>
 507  
                 //<!DOCTYPE todo SYSTEM "todo.dtd" >
 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  
      * Open a ZipInputStream to the first file found with a given extension.
 539  
      *
 540  
      * @param url
 541  
      *            The URL of the zip file.
 542  
      * @param ext
 543  
      *            The required extension.
 544  
      * @return the zip stream positioned at the required location or null
 545  
      * if the requested extension is not found.
 546  
      * @throws IOException
 547  
      *             if there is a problem opening the file.
 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  
      * A stream of input streams for reading the Zipped file.
 576  
      */
 577  
     private static class SubInputStream extends FilterInputStream {
 578  
         private ZipInputStream in;
 579  
 
 580  
         /**
 581  
          * The constructor.
 582  
          *
 583  
          * @param z
 584  
          *            the zip input stream
 585  
          */
 586  
         public SubInputStream(ZipInputStream z) {
 587  0
             super(z);
 588  0
             in = z;
 589  0
         }
 590  
 
 591  
         /*
 592  
          * @see java.io.InputStream#close()
 593  
          */
 594  
         @Override
 595  
         public void close() throws IOException {
 596  0
             in.closeEntry();
 597  0
         }
 598  
 
 599  
         /**
 600  
          * Reads the next ZIP file entry and positions stream at the beginning
 601  
          * of the entry data.
 602  
          *
 603  
          * @return the ZipEntry just read
 604  
          * @throws IOException
 605  
          *             if an I/O error has occurred
 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  
      * Get a list of zip file entries which end with the given extension.
 627  
      * If the extension is null, all entries are returned.
 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  
 }