LocalDirectoryFileContainer.java :  » Development » javaguard » net » sf » javaguard » Java Open Source

Java Open Source » Development » javaguard 
javaguard » net » sf » javaguard » LocalDirectoryFileContainer.java
/**
 * JavaGuard -- an obfuscation package for Java classfiles.
 *
 * Copyright (c) 2002 Thorsten Heit (theit@gmx.de)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * The author may be contacted at theit@gmx.de.
 *
 *
 * $Id: LocalDirectoryFileContainer.java,v 1.5 2002/06/03 16:50:45 glurk Exp $
 */
package net.sf.javaguard;


import java.io.*;
import java.util.*;
import java.util.jar.Manifest;
import org.apache.oro.io.Perl5FilenameFilter;
import org.apache.oro.text.MalformedCachePatternException;
import net.sf.javaguard.classfile.ClassConstants;
import net.sf.javaguard.log.Log;
import net.sf.javaguard.log.ScreenLogger;


/** The purpose of a FileContainer is to ease the handling of a list of files
 * created either from the entries of a Jar file or from the contents of a
 * local directory that match a given regular expression.
 *
 * @author <a href="mailto:theit@gmx.de">Thorsten Heit</a>
 */
public class LocalDirectoryFileContainer implements FileContainer {
  /** The name of the file container. Either the name of the assigned Jar file
   * or the name of the local directory.
   */
  private File directory;
  /** A vector containing all files from the local directory that match the
   * given regular expression.
   */
  private Vector localFiles;
  /** Holds the sorted list of files in the local directory. */
  private SortedSet filenameSet;
  /** The current screen logger. */
  private static ScreenLogger logger = ScreenLogger.getInstance();
  
  
  
  
  /** Creates a new instance of FileContainer to manage the contents of a local
   * directory.
   * @param dir the local directory
   * @param regex a string with a regular expression
   * @throws MalformedCachePatternException if there is an error in compiling
   * the regular expression
   */
  public LocalDirectoryFileContainer(File dir, String regex)
  throws MalformedCachePatternException {
    setDirectory(dir);
    setFileNameSet(null);
    setLocalFiles(new Vector(25, 25));
    createFileList(dir, new Perl5FilenameFilter(regex));
  }
  
  
  
  
  /** Sets the directory for the file container.
   * @param dir the directory for the file container.
   * @see #getDirectory
   */
  private void setDirectory(File dir) {
    this.directory = dir;
  }
  
  
  /** Returns the directory for the file container.
   * @return the directory for the file container
   * @see #setDirectory
   */
  private File getDirectory() {
    return directory;
  }
  
  
  /** Returns the name for the file container. Either the name of the Jar file
   * or the name of the local directory.
   * @return the name for the file container
   */
  public String getName() {
    return getDirectory().getName();
  }
  
  
  
  
  /** Returns the Manifest file for the LocalDirectoryFileContainer. This
   * function is currently not supported; it always returns null.
   * @return Manifest file; always null
   * @throws IOException if an I/O error occurs
   */
  public Manifest getManifest()
  throws IOException {
    return null;
  }
  
  
  
  
  /** Returns a sorted set of the file names in this file container. Each
   * element in the set must be a string in which packages/directories are
   * separated by "/".
   * @return a sorted set of file names; must not be null
   */
  public SortedSet getFileNameSet() {
    if (null == filenameSet) {
      filenameSet = new TreeSet();
      Vector vec = getLocalFiles();
      for (int i=0; i<vec.size(); i++) {
        File file = (File) vec.elementAt(i);
        filenameSet.add(createFilename(file));
      }
    }
    return filenameSet;
  }
  
  
  /** Sets the sorted set with file names of the entries of the Jar file.
   * @param set the sorted set with file names
   * @see #getFileNameSet
   */
  private void setFileNameSet(SortedSet set) {
    this.filenameSet = set;
  }
  
  
  
  
  /** Removes file entries in the current file container that are already
   * contained in the given file container.
   * @param fileContainer the file container to compare to
   */
  public void removeDuplicates(FileContainer fileContainer) {
    // only continue if the given file container is valid and if we have some
    // elements stored in our local file container
    if (null == fileContainer || getLocalFiles().isEmpty()) return;
    logger.log(Log.INFO, "Searching for duplicates in local directory file container '" + getName() + "'");
    
    boolean changed = false;
    if (fileContainer instanceof LocalDirectoryFileContainer) {
      LocalDirectoryFileContainer ldfc = (LocalDirectoryFileContainer) fileContainer;
      // only continue when we have root directories!
      if (null == getDirectory() || null == ldfc.getDirectory()) return;
      // first compare the root directories of the local file containers
      String str1 = createFilename(getDirectory());
      String str2 = createFilename(ldfc.getDirectory());
      // if no root directory is a prefix of the other one we can stop because
      // the file lists are disjunct
      if (!str1.startsWith(str2) && !str2.startsWith(str1)) return;
      // walk through the local list of files and check whether class files
      // are already contained in the other set so they can safely be removed
      // from our set
      SortedSet fileSet = ldfc.getFileNameSet();
      Vector localFiles = getLocalFiles();
      for (int i=0; i<localFiles.size(); i++) {
        File file = (File) localFiles.elementAt(i);
        String str = createFilename(file);
        // if the other fileset contains the file's name remove it from the
        // local list
        if (fileSet.contains(str)) {
          logger.log(Log.VERBOSE, "Removing entry '" + str + "' from file container");
          localFiles.removeElementAt(i);
          i--; // because we just removed one element...
          changed = true;
        }
      }
    } else if (fileContainer instanceof JarFileContainer) {
      SortedSet fileSet = fileContainer.getFileNameSet();
      Vector localfiles = getLocalFiles();
      // iterate each element of the other file container
      Iterator iter = fileSet.iterator();
      while (iter.hasNext()) {
        String className = (String) iter.next();
        // check whether the local file list contains a file that equals the
        // actual name, i.e. whether a local file ends with the actual name
        for (int i=0; i<localFiles.size(); i++) {
          File file = (File) localFiles.elementAt(i);
          String fileName = createFilename(file);
          if (fileName.endsWith(className)) {
            logger.log(Log.VERBOSE, "Removing entry '" + className + "' from file container");
            localFiles.removeElementAt(i);
            i--; // because we just removed one element...
            changed = true;
            break;
          }
        }
      }
    } else {
      throw new IllegalArgumentException("Unknown type of file container: " + fileContainer.getClass());
    }
    // if the file list has changed reset the tree set that holds the sorted
    // list of files
    if (changed) {
      setFileNameSet(null);
    }
  }
  
  
  
  
  /** Returns an enumeration of the elements of the file container. The
   * <code>nextElement()</code> method of such an enumeration must return a
   * subclass of {@link FileEntry}.
   * @return an enumeration of the elements of the file container
   */
  public Enumeration enumeration() {
    return new LocalDirectoryFileEnumeration(getLocalFiles().elements());
  }
  
  
  
  
  /** Adds the list of files under the given subdirectory to the current list
   * of files.
   * @param dir the start directory
   * @param regex the regular expression
   */
  private void createFileList(File dir, Perl5FilenameFilter regex) {
    if (null != dir && null != regex) {
      File[] filelist = dir.listFiles();
      if (null != filelist) {
        for (int i=0; i<filelist.length; i++) {
          if (filelist[i].isDirectory()) {
            // recursively walk through the tree
            createFileList(filelist[i], regex);
          } else {
            if (regex.accept(filelist[i])) {
              addLocalFile(filelist[i]);
            }
          }
        }
      }
    }
  }
  
  
  
  
  /** Sets the vector that holds the list of files contained in a local
   * directory.
   * @param vec vector that will hold the files
   * @see #getLocalFiles
   */
  private void setLocalFiles(Vector vec) {
    this.localFiles = vec;
  }
  
  
  /** Returns the vector that holds the list of files in a local directory.
   * @return vector that holds the list of files; always non-null
   * @see #setLocalFiles
   */
  Vector getLocalFiles() {
    if (null == localFiles) {
      localFiles = new Vector();
    }
    return localFiles;
  }
  
  
  /** Adds a local file to the list of available local files.
   * @param file the file to add to the list of local files
   */
  private void addLocalFile(File file) {
    getLocalFiles().addElement(file);
  }
  
  
  
  
  /** Checks whether the given file name represents a Java class, i.e. checks
   * whether the file name ends with ".class".
   * @param file the file to check
   * @return true if the file is a class file; false else
   * @see #isClassFile(String)
   */
  private static boolean isClassFile(File file) {
    return isClassFile(file.getAbsolutePath());
  }
  
  
  /** Checks whether the given string represents a Java class, i.e. checks
   * whether it ends with ".class".
   * @param str the string to check
   * @return true if the string represents the name of a class file; false else
   */
  private static boolean isClassFile(String str) {
    return str.endsWith(ClassConstants.CLASS_EXT);
  }
  
  
  /** Returns the name of the given file as a string. If possible the canonical
   * form is used, otherwise the absolute path name is returned.
   * @param file the file whose name should be returned
   * @return the name of the given file as a string
   */
  static String createFilename(File file) {
    String str;
    try {
      // try to return the canonical path
      str = file.getCanonicalPath();
    } catch (IOException ioex) {
      // if not possible use the absolute path
      str = file.getAbsolutePath();
    }
    // replace the directory separator characters by a "/"
    return str.replace(File.pathSeparatorChar, '/');
  }
  
  
  
  
  /** A data structure that holds a file entry.
   */
  private class LocalDirectoryFileEnumeration implements Enumeration {
    /** Holds the enumeration of available local files. */
    Enumeration enumeration;
    /** Holds the next file entry to return in <code>nextElement</code>. */
    FileEntry entry = null;
    
    
    /** Creates a new local file entry enumeration.
     * @param enum a valid enumeration of File objects
     */
    LocalDirectoryFileEnumeration(Enumeration enum) {
      setEnumeration(enum);
    }
    
    
    /** Tests if this enumeration contains more elements.
     * @return true if and only if this enumeration object contains at least
     * one more element to provide; false otherwise
     */
    public boolean hasMoreElements() {
      if (null == getEntry()) {
        fetchNextEntry();
      }
      return null != getEntry();
    }
    
    
    /** Returns the next element of this enumeration if this enumeration object
     * has at least one more element to provide.
     * @return the next element of this enumeration as a {@link FileEntry}
     * object if at least one more element is available; null if no elements
     * are left in the enumeration or an error has occured
     */
    public Object nextElement() {
      FileEntry retVal;
      if (null == getEntry()) {
        fetchNextEntry();
      }
      retVal = getEntry();
      setEntry(null);
      return retVal;
    }
    
    
    /** Creates a {@link FileEntry} object for the next element in the
     * enumeration.
     */
    private void fetchNextEntry() {
      FileEntry entry = null;
      if (getEnumeration().hasMoreElements()) {
        File file = (File) getEnumeration().nextElement();
        try {
          String name;
          try {
            name = file.getCanonicalPath();
          } catch (IOException ioex) {
            // if it's not possible to receive the canonical name of the file
            // just take the absolute path name
            name = file.getAbsolutePath();
          }
          entry = new FileEntry(new DataInputStream(new FileInputStream(file)),
          name, isClassFile(file), file.length());
        } catch (FileNotFoundException fnfex) {
          // should never happen because we've created the file list before
          // we access the getNextEntry() function
          logger.println("File not found: " + file.getName());
        }
      }
      setEntry(entry);
    }
    
    
    /** Stores the given {@link FileEntry} object.
     * @param fileEntry the file entry object to store
     * @see #getEntry
     */
    private void setEntry(FileEntry fileEntry) {
      this.entry = fileEntry;
    }
    
    
    /** Returns the file entry object.
     * @return file entry object
     * @see #setEntry
     */
    private FileEntry getEntry() {
      return entry;
    }
    
    
    
    
    /** Stores the current enumeration.
     * @param enum the enumeration
     * @see #getEnumeration
     */
    private void setEnumeration(Enumeration enum) {
      this.enumeration = enum;
    }
    
    
    /** Returns the current enumeration.
     * @return the current enumeration
     * @see #setEnumeration
     */
    private Enumeration getEnumeration() {
      return enumeration;
    }
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.