krysalis-update/src/java/org/krysalis/depot/common/util/classpath PathWalker.java,NONE,1.1 PathSet.java,NONE,1.1 PathPart.java,NONE,1.1 PathContext.java,NONE,1.1

Nick Chalko <[email protected]> Wed, 08 Dec 2004 09:06:40 +0000
Newsgroups gmane.comp.krysalis.cvs
Message-ID <[email protected]>
Update of /cvsroot/krysalis/krysalis-update/src/java/org/krysalis/depot/common/util/classpath
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24726/src/java/org/krysalis/depot/common/util/classpath

Added Files:
	PathWalker.java PathSet.java PathPart.java PathContext.java 
Log Message:
Copied from the apache incubator.

--- NEW FILE: PathContext.java ---
/*
 * Copyright  2004 The Apache Software Foundation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.krysalis.depot.common.util.classpath;

import java.io.PrintWriter;

import org.krysalis.depot.common.util.debug.DebugUtils;
import org.krysalis.depot.common.util.debug.Dumpable;
import org.krysalis.depot.common.util.dom.DOMProducer;
import org.krysalis.depot.common.util.dom.DOMUtils;
import org.krysalis.depot.common.util.envsafe.ClassLoaderContext;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * @author arb_jack
 */
public class PathContext implements Dumpable, DOMProducer {
	private PathSet m_pathSet = null;
	private ClassLoaderContext m_loaderContext = null;

	public PathContext() {
		m_pathSet = PathSet.getClasspath();
		
		m_loaderContext = new ClassLoaderContext(ClassLoader.getSystemClassLoader());		
		classInit();
	}

	public PathContext(PathSet pathSet) {
		m_pathSet = pathSet;
		m_loaderContext = new ClassLoaderContext(ClassLoader.getSystemClassLoader());
		classInit();
	}

	public PathContext(ClassLoader classloader) {
		m_pathSet = PathSet.getClasspath();
		m_loaderContext = new ClassLoaderContext(classloader);

		classInit();
	}

	public PathContext(PathSet pathSet, ClassLoader classloader) {
		m_pathSet = pathSet;
		m_loaderContext = new ClassLoaderContext(classloader);
		
		classInit();
	}

	private void classInit() {
	}

	/**
	 * @return
	 */
	public PathSet getPathSet() {
		return m_pathSet;
	}

	/**
	 * @return
	 */
	public ClassLoaderContext getClassLoaderContext() {
		return m_loaderContext;
	}

	/**
	 * @return
	 */
	public ClassLoader getClassLoader() {
		return m_loaderContext.getClassLoader();
	}

	/* 
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	public boolean equals(Object other) {
		boolean equal = false;

		if (other instanceof PathContext) {
			PathContext otherPathContext = (PathContext) other;

			//:TODO: Compare hierarchies also ???...
			equal = otherPathContext.m_loaderContext.equals(m_loaderContext);

			if (equal)
				equal = otherPathContext.m_pathSet.equals(m_pathSet);
		}
		else
			throw new IllegalArgumentException(
				"Not a PathContext: " + other.getClass().getName());

		return equal;
	}

	/* 
	 * @see java.lang.Object#hashCode()
	 */
	public int hashCode() {
		return m_pathSet.hashCode() + m_loaderContext.hashCode();
	}

	public void dump(PrintWriter out, int depth, boolean verbose) {
		dumpClassLoader(out, depth, m_loaderContext.getClassLoader());
		m_pathSet.dump(out, depth, verbose);
	}

	
	private void dumpClassLoader(
		PrintWriter out,
		int depth,
		ClassLoader classloader) {

		String indent = DebugUtils.getIndent(depth);

		out.print(indent);
		out.print(classloader.getClass().getName());
		out.print(" : ");
		out.println(classloader.toString());

		if (null != classloader.getParent()) {
			dumpClassLoader(out, depth + 1, classloader.getParent());
		}
	}

	public void produceDOM(Document document, Element element) {
		Element pc = DOMUtils.insertElement(document,element,"PathContext");
		produceClassloaderDOM(document, pc, m_loaderContext.getClassLoader());
		m_pathSet.produceDOM(document, pc);
	}

	private void produceClassloaderDOM(
		Document document,
		Element element,
		ClassLoader classloader) {

		Element cl = DOMUtils.insertElement(document, element, "Classloader");
		DOMUtils.insertAttribute(
			document,
			cl,
			"type",
			classloader.getClass().getName());
		DOMUtils.insertText(document, cl, classloader.toString());

		if (null != classloader.getParent()) {
			produceClassloaderDOM(document, cl, classloader.getParent());
		}
	}
}

--- NEW FILE: PathPart.java ---
/*
 * Copyright  2004 The Apache Software Foundation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.krysalis.depot.common.util.classpath;

import java.io.File;

/**
 * @author ajack
 */
public class PathPart {

	private File m_part = null;

	public PathPart(String base, String part) {
		m_part = new File(base, part);
	}

	public PathPart(File part) {
		m_part = part;
	}

	public PathPart(String part) {
		m_part = new File(part);
	}

	/**
	 * Returns the part.
	 * @return String
	 */
	public File getPart() {
		return m_part;
	}

	/**
	 * Sets the part.
	 * @param part The part to set
	 */
	public void setPart(File file) {
		m_part = file;
	}

	public String toString() {
		return m_part.getAbsolutePath();
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	public boolean equals(Object obj) {
		boolean equal = false;

		if (obj instanceof PathPart) {
			equal = m_part.equals(((PathPart) obj).m_part);
		}

		return equal;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	public int hashCode() {
		return m_part.hashCode();
	}
}

--- NEW FILE: PathWalker.java ---
/*
 * Copyright  2004 The Apache Software Foundation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */


package org.krysalis.depot.common.util.classpath;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

import org.krysalis.depot.common.log.Logger;
import org.krysalis.depot.common.util.Tuple;
import org.krysalis.depot.common.util.classpath.listener.DirectoryListener;
import org.krysalis.depot.common.util.classpath.listener.DropListener;
import org.krysalis.depot.common.util.classpath.listener.FileContentsListener;
import org.krysalis.depot.common.util.classpath.listener.FileListener;
import org.krysalis.depot.common.util.classpath.listener.JarListener;
import org.krysalis.depot.common.util.classpath.listener.ManifestListener;
import org.krysalis.depot.common.util.classpath.listener.NameFilter;

//
// :TODO: Load the JAR using the current classloader (to get right one)
//

/**
 *
 * @author Adam R. B. Jack. 
 */
public class PathWalker {

	private final static File ROOT = new File("/");

	//
	//
	//
	private PathSet m_pathSet = null;

	//
	// Listeners
	//
	private ArrayList m_fileListeners = null;
	private ArrayList m_fileContentsListeners = null;
	private ArrayList m_directoryListeners = null;
	private ArrayList m_jarListeners = null;
	private ArrayList m_manifestListeners = null;

	private ArrayList m_dropListeners = null;

	/**
	 * @param base -- $CWD for this activity
	 * @param pathSet
	 */
	public PathWalker(PathSet pathSet) {
		m_pathSet = pathSet;
		initialize();
	}

	private void initialize() {
	}

	public void registerListener(Object listener) {
		registerListener(listener, null);
	}

	public void registerListener(Object listener, Object context) {
		if (listener instanceof ManifestListener)
			registerManifestListener((ManifestListener) listener, context);

		if (listener instanceof JarListener)
			registerJarListener((JarListener) listener, context);

		if (listener instanceof FileListener)
			registerFileListener((FileListener) listener, context);

		if (listener instanceof FileContentsListener)
			registerFileContentsListener(
				(FileContentsListener) listener,
				context);

		if (listener instanceof DirectoryListener)
			registerDirectoryListener((DirectoryListener) listener, context);

		if (listener instanceof DropListener)
			registerDropListener((DropListener) listener, context);
	}

	public void registerFileListener(
		FileListener fileListener,
		Object context) {
		if (null == m_fileListeners)
			m_fileListeners = new ArrayList();

		m_fileListeners.add(new Tuple(fileListener, context));
	}

	public void registerFileContentsListener(
		FileContentsListener fileContentsListener,
		Object context) {
		if (null == m_fileContentsListeners)
			m_fileContentsListeners = new ArrayList();

		m_fileContentsListeners.add(new Tuple(fileContentsListener, context));
	}

	public void registerDirectoryListener(
		DirectoryListener dirListener,
		Object context) {
		if (null == m_directoryListeners)
			m_directoryListeners = new ArrayList();

		m_directoryListeners.add(new Tuple(dirListener, context));
	}

	public void registerDropListener(
		DropListener dropListener,
		Object context) {
		if (null == m_dropListeners)
			m_dropListeners = new ArrayList();

		m_dropListeners.add(new Tuple(dropListener, context));
	}

	public void registerManifestListener(
		ManifestListener manifestListener,
		Object context) {
		if (null == m_manifestListeners)
			m_manifestListeners = new ArrayList();

		m_manifestListeners.add(new Tuple(manifestListener, context));
	}

	public void registerJarListener(JarListener jarListener, Object context) {
		if (null == m_jarListeners)
			m_jarListeners = new ArrayList();

		m_jarListeners.add(new Tuple(jarListener, context));
	}

	/**
	 * 
	 */
	public void walk() {

//		System.out.println("Walk the path....");

		// Anything to do?
		if ((null == m_fileListeners)
			&& (null == m_fileContentsListeners)
			&& (null == m_manifestListeners)
			&& (null == m_directoryListeners)
			&& (null == m_jarListeners))
			return;

		//
		// Sanitize the pathset
		// :TODO: Bad Side Effect?
		//
		List dropList = m_pathSet.sanitize();
		if (null != m_dropListeners)
			processDrops(dropList);

		boolean searchJarContents =
			(null != m_fileListeners)
				|| (null != m_fileContentsListeners)
				|| (null != m_manifestListeners)
				|| (null != m_directoryListeners);

		boolean searchDirContents =
			(null != m_fileListeners) || (null != m_fileContentsListeners);

		for (Iterator parts = m_pathSet.iterator(); parts.hasNext();) {
			PathPart pathPart = (PathPart) parts.next();
			//
			//    Get an abstract file for this.
			//
			//    Todo -- Hmm, load via class loader?
			//
			File file = pathPart.getPart();
			String fileName = file.getAbsolutePath();

//			System.out.println("File:" + file);

			if (file.exists()) {
				if (file.isFile()) {
					//
					// Process This file
					//
					if (fileName.endsWith(".jar")) {
						processJar(file, fileName);

						if (searchJarContents)
							walkIntoJAR(file);
					}
					else
						processFile(file, ROOT, fileName);
				}
				else {
					//
					// Process This file
					//
					processDirectory(file, fileName);

					if (searchDirContents)
						walkIntoDirectory(file);
				}
			}
			else {
				//:TODO: add a "sanitize" path -- someday, this is too
				// verbose...
				Logger.getLogger().debug(
					"Invalid part in path [" + file + "]");
			}
		}
	}

	private void walkIntoJAR(File jar) {
//		System.out.println("Walk JAR: " + jar);

		try {
			JarFile jf = new JarFile(jar);

			Manifest manifest = jf.getManifest();

			if ((null != manifest) && (null != m_manifestListeners)) {
				//System.out.println("Process Manifest: " + manifest);
				processManifest(jar, manifest);
			}

			if (null != m_fileListeners) {
				for (Enumeration e = jf.entries(); e.hasMoreElements();) {

					JarEntry entry = (JarEntry) e.nextElement();

					//System.out.println("Entry: " + entry);

					File entryFile = new File(entry.getName());

					if (null != m_fileListeners)
						processFile(entryFile, ROOT, "JAR:" + jar.getName());

					if (null != m_fileContentsListeners) {

						if (!filter(entry.getName(),
							m_fileContentsListeners)) {
							InputStream contents = null;
							try {
								contents = jf.getInputStream(entry);

								processFileContents(
									entryFile,
									ROOT,
									contents,
									"JAR:" + jar.getName());
							}
							finally {
								if (null != contents)
									try {
										contents.close();
									}
									catch (Exception ee) {
									};
							}
						}
					}
				}
			}
		}
		catch (Throwable t) {Logger.getLogger().error("Throwable:" + jar + ")", t);
		}
	}

	private void walkIntoDirectory(File directory) {
		walkIntoDirectory(directory, null, directory);
	}

	private void walkIntoDirectory(File directory, String path, File root) {
		//System.out.println("Walk Directory: " + directory + "\t" + root);

		String[] files = directory.list();

		if ((null != files) && (null != m_fileListeners))
			for (int i = 0; i < files.length; i++) {
				String fileName = files[i];

				String pathName =
					(null != path) ? path + "/" + fileName : fileName;
				File file = new File(root, pathName);

				if (file.exists()) {
					if (file.isFile()) {
						processFile(
							file,
							root,
							"File:" + directory.getAbsolutePath());

						if (null != m_fileContentsListeners) {

							if (!filter(fileName, m_fileContentsListeners)) {
								InputStream contents = null;
								try {
									File absoluteFile =
										new File(root, pathName);

									contents =
										new FileInputStream(
											absoluteFile.getAbsoluteFile());

									processFileContents(
										file,
										root,
										contents,
										"File:" + file);
								}
								catch (Exception fe) {
									Logger.getLogger().error(
										"Exception opening file: " + file,
										fe);
								}
								finally {
									if (null != contents)
										try {
											contents.close();
										}
										catch (Exception ee) {
										};
								}
							}
						}
					}
					else {
						String dirName = file.getName();
						String subPath =
							((null != path) ? path + "." + dirName : dirName);
						walkIntoDirectory(file, subPath, root);
					}
				}
				else
					Logger.getLogger().debug(
						"Invalid part in path [" + file + "]");
			}
	}

	private void processDirectory(File directory, String location) {
		for (Iterator listeners = m_directoryListeners.iterator();
			listeners.hasNext();
			) {
			Tuple tuple = (Tuple) listeners.next();
			DirectoryListener listener = (DirectoryListener) tuple.getFirst();
			Object context = tuple.getSecond();

			//
			// Filter (or not) based off name
			//
			boolean filter = false;

			if (listener instanceof NameFilter)
				filter =
					((NameFilter) listener).filter(
						directory.getAbsolutePath(),
						context);

			if (!filter)
				listener.processDirectory(
					tuple.getSecond(),
					directory,
					location);
		}
	}

	private void processJar(File file, String location) {
		for (Iterator listeners = m_jarListeners.iterator();
			listeners.hasNext();
			) {
			Tuple tuple = (Tuple) listeners.next();

			JarListener listener = (JarListener) tuple.getFirst();
			Object context = tuple.getSecond();

			//
			// Filter (or not) based off name
			//
			boolean filter = false;

			if (listener instanceof NameFilter)
				filter =
					((NameFilter) listener).filter(
						file.getAbsolutePath(),
						context);

			if (!filter)
				listener.processJar(tuple.getSecond(), file, location);
		}
	}

	private void processManifest(File file, Manifest manifest) {
		for (Iterator listeners = m_manifestListeners.iterator();
			listeners.hasNext();
			) {
			Tuple tuple = (Tuple) listeners.next();

			ManifestListener listener = (ManifestListener) tuple.getFirst();
			Object context = tuple.getSecond();

			//
			// Filter (or not) based off name
			//
			boolean filter = false;

			if (listener instanceof NameFilter)
				filter =
					((NameFilter) listener).filter(
						file.getAbsolutePath(),
						context);

			if (!filter)
				listener.processManifest(tuple.getSecond(), file, manifest);
		}
	}

	private void processFile(File file, File rootDir, String location) {

		Logger.getLogger().debug(
			"Process File:" + file + "[" + location + "]");

		//System.out.println(
		//			"Process File:" + file + "[" + location + "]");

		for (Iterator listeners = m_fileListeners.iterator();
			listeners.hasNext();
			) {

			//
			// This listener w/ their context
			//
			Tuple tuple = (Tuple) listeners.next();

			FileListener listener = ((FileListener) (tuple.getFirst()));
			Object context = tuple.getSecond();

			//
			// Filter (or not) based off name
			//
			boolean filter = false;

			if (listener instanceof NameFilter)
				filter =
					((NameFilter) listener).filter(
						file.getAbsolutePath(),
						context);

			if (!filter) {
				listener.processFile(context, file, rootDir, location);
			}
		}
	}

	private void processDrops(List list) {

		for (Iterator dropies = list.iterator(); dropies.hasNext();) {
			PathPart entity = (PathPart) dropies.next();

			Logger.getLogger().debug("Process Drop:" + entity + "]");

			for (Iterator listeners = m_dropListeners.iterator();
				listeners.hasNext();
				) {

				//
				// This listener w/ their context
				//
				Tuple tuple = (Tuple) listeners.next();

				DropListener listener = ((DropListener) (tuple.getFirst()));
				listener.processDropped(tuple.getSecond(), entity);
			}
		}
	}

	private void processFileContents(
		File file,
		File rootDir,
		InputStream fileContents,
		String location) {

		Logger.getLogger().debug(
			"Process File:" + file + "[" + location + "]");

		int readers = 0;
		for (Iterator listeners = m_fileContentsListeners.iterator();
			listeners.hasNext();
			) {

			//
			// This listener w/ their context
			//
			Tuple tuple = (Tuple) listeners.next();

			FileContentsListener listener =
				((FileContentsListener) (tuple.getFirst()));
			Object context = tuple.getSecond();

			//
			// Filter (or not) based off name
			//
			boolean filter = false;

			if (listener instanceof NameFilter)
				filter =
					((NameFilter) listener).filter(
						file.getAbsolutePath(),
						context);

			if (!filter) {

				if (++readers > 1) {
					//:TODO: Nasty bug w/ contents already read, can't
					// easily reset to start, have to re-code to open 
					// each time. Harder for in JAR...
					throw new IllegalStateException("Can't have two readers on one stream, need to re-code.");
				}

				listener.processFile(
					context,
					file,
					rootDir,
					fileContents,
					location);
			}
		}
	}

	private boolean filterFile(String name) {
		boolean filter = true;

		if (filter)
			filter = filter(name, m_fileListeners);

		if (filter)
			filter = filter(name, m_fileContentsListeners);

		return filter;
	}

	/**
	 * 
	 * Goes throgu a list of listeners and *ALL* are NameFilters
	 * and *ALL* don't want it, return "true".
	 * 
	 * @param name
	 * @param listenerList
	 * @return
	 */
	private boolean filter(String name, List listenerList) {
		boolean filter = true;

		for (Iterator listeners = listenerList.iterator();
			listeners.hasNext() && filter;
			) {

			//
			// This listener w/ their context
			//
			Tuple tuple = (Tuple) listeners.next();

			Object listener = tuple.getFirst();
			Object context = tuple.getSecond();

			if (listener instanceof NameFilter) {
				filter &= ((NameFilter) listener).filter(name, context);
			}
			else
				filter = false;
		}
		return filter;
	}

	/**
	 * Returns the pathSet.
	 * @return PathSet
	*/
	public PathSet getPathSet() {
		return m_pathSet;
	}

	/**
	 * Sets the pathSet.
	 * @param pathSet The pathSet to set
	*/
	public void setPathSet(PathSet pathSet) {
		m_pathSet = pathSet;
	}
}

--- NEW FILE: PathSet.java ---
/*
 * Copyright  2004 The Apache Software Foundation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.krysalis.depot.common.util.classpath;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

import org.krysalis.depot.common.log.Logger;
import org.krysalis.depot.common.util.SystemUtils;
import org.krysalis.depot.common.util.collection.EntityList;
import org.krysalis.depot.common.util.dom.DOMUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * @author ajack
 */
public class PathSet extends EntityList {

	private boolean m_changed = false;
	private String m_baseDir = null;

	public static PathSet getClasspath() {

		PathSet boot = PathSet.getSystemBootClasspath();
		PathSet sys = PathSet.getSystemClasspath();

		PathSet combo = new PathSet("SystemAndBootClasspaths");

		boot.uniqifyOnDemand();
		combo.addAll(boot);

		sys.uniqifyOnDemand();
		combo.addAll(sys);

		return combo;
	}

	public static PathSet getSystemClasspath() {
		String classPath = SystemUtils.getSystemProperty("java.class.path");

		Logger.getLogger().debug("Class Path: " + classPath);

		return new PathSet("SystemClasspath", classPath);
	}

	public static PathSet getSystemBootClasspath() {
		String bootClassPath =
			SystemUtils.getSystemProperty("sun.boot.class.path");

		Logger.getLogger().debug("Boot Class Path: " + bootClassPath);

		return new PathSet("BootClasspath", bootClassPath);
	}

	public PathSet(String id) {
		super(id);
		m_baseDir = getCurrentWorkingDirectory();
	}

	public PathSet(String id, String path) {
		super(id);
		m_baseDir = getCurrentWorkingDirectory();
		importPath(path);
	}

	public PathSet(String id, String baseDir, String path) {
		super(id);
		m_baseDir = baseDir;
		importPath(path);
	}

	/**
	 * @param id
	 * @param initialCapacity
	 */
	public PathSet(String id, int initialCapacity) {
		super(id, initialCapacity);
		m_baseDir = getCurrentWorkingDirectory();
	}

	public PathSet(String id, Collection collection) {
		super(id);
		m_baseDir = getCurrentWorkingDirectory();

		for (Iterator iterator = collection.iterator(); iterator.hasNext();) {
			add(iterator.next());
		}
	}

	private String getCurrentWorkingDirectory() {
		String cwd = SystemUtils.getSystemProperty("user.dir");
		return cwd;
	}

	public void importPath(String path) {
		for (StringTokenizer tokens =
			new StringTokenizer(path, SystemUtils.g_pathSeparator);
			tokens.hasMoreTokens();
			) {
			add(tokens.nextToken());
		}
	}

	public void importPathSet(PathSet pathSet) {
		for (Iterator iterator = pathSet.iterator(); iterator.hasNext();) {
			add(iterator.next());
		}
	}

	public List sanitize() {
		List dropList = new ArrayList();
		for (Iterator iter = iterator(); iter.hasNext();) {
			PathPart pathPart = (PathPart) iter.next();
			try {
				//:TODO: From base?
				File partFile = pathPart.getPart();

				if (!partFile.exists() || !partFile.canRead()) {
					dropList.add(pathPart);
				}
			}
			catch (Exception e) {
				dropList.add(pathPart);
			}
		}

		//
		// Drop those dodgy ones...
		//
		for (Iterator di = dropList.iterator(); di.hasNext();) {
			PathPart pathPart = (PathPart) di.next();
			remove(pathPart);
		}

		return dropList;
	}

	public Iterator iterator() {
		//
		// Atempt to remove duplicates
		//
		if (m_changed)
			uniqifyOnDemand();

		return super.iterator();
	}

	public void uniqifyOnDemand() {
		if (m_changed) {

			// Must have more than one to need doing...
			if (size() > 1)
				uniqify();

			m_changed = false;
		}
	}

	/**
	 * Make a unqiue set of contents, removing duplicates.
	 */
	public void uniqify() {
		EntityList newParts = new EntityList("PathSet");

		//
		// Remove duplicates, but preserve order..
		//
		HashSet set = new HashSet();

		for (Iterator i = super.iterator(); i.hasNext();) {
			PathPart part = (PathPart) i.next();

			if (!set.contains(part)) {
				newParts.add(part);
				set.add(part);
			}
			else
				Logger.getLogger().debug("Drop duplicate: " + part);
		}

		clear();
		addAll(newParts);
	}

	//:TODO: Allow a "strong check" (uniquify/order) to see if two of
	// these are the same, could save a lot of performance... 

	//:TODO: add hash and equal, hmm - -they done for me?
	// what about (1) uniqify (2) sort (3) compare...

	public boolean add(Object partObject) {
		PathPart part = null;

		if (partObject instanceof PathPart)
			part = (PathPart) partObject;
		if (partObject instanceof File)
			part = new PathPart((File)partObject);
		if (partObject instanceof String)
			part = new PathPart((String)partObject);

		m_changed = true;

		return super.add(part);
	}

	/* (non-Javadoc)
	 * @see java.util.List#add(int, java.lang.Object)
	 */
	public void add(int posn, Object partObject) {
		PathPart part = null;

		if (partObject instanceof PathPart)
			part = (PathPart) partObject;
		if (partObject instanceof File)
			part = new PathPart((File)partObject);
		if (partObject instanceof String)
			part = new PathPart((String)partObject);

		m_changed = true;

		super.add(posn, part);
	}

	/* (non-Javadoc)
	 * @see java.util.Collection#addAll(java.util.Collection)
	 */
	public boolean addAll(Collection arg0) {
		m_changed = true;
		return super.addAll(arg0);
	}

	/* (non-Javadoc)
	 * @see java.util.List#addAll(int, java.util.Collection)
	 */
	public boolean addAll(int arg0, Collection arg1) {
		m_changed = true;
		return super.addAll(arg0, arg1);
	}
	

	public void produceDOM(Document document, Element element) {
		Element ps = DOMUtils.insertElement(document,element,"PathSet");
		DOMUtils.insertAttribute(document,ps,"name",getName());
		DOMUtils.produceDOM(document, ps, iterator());
	}
}



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now. 
http://productguide.itmanagersjournal.com/