private void open() {
   // Create all jar files
   _jars = new ArrayList<JarFile>(_files.size());
   for (File f : _files) {
     try {
       JarFile jar = new JarFile(f);
       _jars.add(jar);
     } catch (IOException ioe) {
       TapestryCore.logError(
           ErrorMessages.UNABLE_TO_CREATE_JAR_FILE_FOR_FILE + f, ioe); // $NON-NLS-1$
     }
   }
 }
  public synchronized void close() {
    if (!_open) return;
    _open = false;

    for (JarCLInputStream st : _openStreams) {
      try {
        st.close();
      } catch (IOException ioe) {
        TapestryCore.logError(ErrorMessages.FAILED_TO_CLOSE_STREAM, ioe); // $NON-NLS-1$
      }
    }
    _openStreams = null;

    for (JarFile jar : _jars) {
      try {
        jar.close();
      } catch (IOException ioe) {
        TapestryCore.logError(ErrorMessages.FAILED_TO_CLOSE_JAR + jar, ioe); // $NON-NLS-1$
      }
    }
    _jars = null;
  }
  @Override
  public synchronized InputStream getResourceAsStream(String name) {
    InputStream input = getParent().getResourceAsStream(name);
    if (input != null) return input;

    if (!_open) return null;

    for (JarFile j : _jars) {
      try {
        ZipEntry entry = j.getEntry(name);
        if (entry != null) {
          InputStream zipInput = j.getInputStream(entry);
          return openInputStream(zipInput);
        }
      } catch (IOException ioe) {
        TapestryCore.logError(ErrorMessages.UNABLE_TO_GET_ENTRY_FROM_JAR + j, ioe); // $NON-NLS-1$
      }
    }
    return null;
  }