[jboss-cvs] jbosside/core/plugins/org.jboss.ide.eclipse.archives.core/src/main/org/jboss/ide/eclipse/archives/core/model/internal ...

Robert Stryker rob.stryker at jboss.com
Wed Apr 18 17:07:52 EDT 2007


  User: rawb    
  Date: 07/04/18 17:07:52

  Added:       core/plugins/org.jboss.ide.eclipse.archives.core/src/main/org/jboss/ide/eclipse/archives/core/model/internal        
                        ArchiveFolderImpl.java ArchiveNodeDeltaImpl.java
                        ArchiveDeltaPreNodeFactory.java
                        ArchiveFileSetImpl.java ArchiveImpl.java
                        ArchiveModelNode.java ArchivesModel.java
                        ArchiveNodeImpl.java
  Log:
  Given it's own module under the new name
  
  Revision  Changes    Path
  1.1      date: 2007/04/18 21:07:52;  author: rawb;  state: Exp;jbosside/core/plugins/org.jboss.ide.eclipse.archives.core/src/main/org/jboss/ide/eclipse/archives/core/model/internal/ArchiveFolderImpl.java
  
  Index: ArchiveFolderImpl.java
  ===================================================================
  /*
   * JBoss, a division of Red Hat
   * Copyright 2006, Red Hat Middleware, LLC, and individual contributors as indicated
   * by the @authors tag. See the copyright.txt in the distribution for a
   * full listing of individual contributors.
   *
   * This 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.1 of
   * the License, or (at your option) any later version.
   *
   * This software 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 software; if not, write to the Free
   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   */
  package org.jboss.ide.eclipse.archives.core.model.internal;
  
  import org.eclipse.core.runtime.IPath;
  import org.jboss.ide.eclipse.archives.core.model.IArchive;
  import org.jboss.ide.eclipse.archives.core.model.IArchiveFileSet;
  import org.jboss.ide.eclipse.archives.core.model.IArchiveFolder;
  import org.jboss.ide.eclipse.archives.core.model.IArchiveNode;
  import org.jboss.ide.eclipse.archives.core.model.internal.xb.XbFolder;
  
  /**
   * A PackageFolderImpl.
   * 
   * @author <a href="marshall at jboss.org">Marshall Culpepper</a>
   * @version $Revision: 1.1 $
   */
  public class ArchiveFolderImpl extends ArchiveNodeImpl implements
  		IArchiveFolder {
  
  	private XbFolder folderDelegate;
  	
  	public ArchiveFolderImpl() {
  		this(new XbFolder());
  	}
  	public ArchiveFolderImpl(XbFolder delegate) {
  		super(delegate);
  		this.folderDelegate = delegate;
  	}
  
  	public String getName() {
  		return folderDelegate.getName();
  	}
  
  	public IArchiveFileSet[] getFileSets() {
  		IArchiveNode nodes[] = getChildren(TYPE_ARCHIVE_FILESET);
  		IArchiveFileSet filesets[] = new IArchiveFileSet[nodes.length];
  		System.arraycopy(nodes, 0, filesets, 0, nodes.length);
  		return filesets;
  	}
  
  	public IArchiveFolder[] getFolders() {
  		IArchiveNode nodes[] = getChildren(TYPE_ARCHIVE_FOLDER);
  		IArchiveFolder folders[] = new IArchiveFolder[nodes.length];
  		System.arraycopy(nodes, 0, folders, 0, nodes.length);
  		return folders;
  	}
  	public IArchive[] getArchives() {
  		IArchiveNode nodes[] = getChildren(TYPE_ARCHIVE);
  		IArchive pkgs[] = new IArchive[nodes.length];
  		System.arraycopy(nodes, 0, pkgs, 0, nodes.length);
  		return pkgs;
  	}
  
  	public int getNodeType() {
  		return TYPE_ARCHIVE_FOLDER;
  	}
  
  	public void addFileSet(IArchiveFileSet fileset) {
  		addChild(fileset);
  	}
  
  	public void addFolder(IArchiveFolder folder) {
  		addChild(folder);
  	}
  
  	public void addPackage(IArchive pkg) {
  		addChild(pkg);
  	}
  
  	public void setName(String name) {
  		attributeChanged(NAME_ATTRIBUTE, getName(), name);
  		folderDelegate.setName(name);
  	}
  
  	protected XbFolder getFolderDelegate ()
  	{
  		return folderDelegate;
  	}
  	
  	public String toString() {
  		return "folder[" + getName() + "]";
  	}
  	public IPath getRootArchiveRelativePath() {
  		return getParent().getRootArchiveRelativePath().append(getName());
  	}
  }
  
  
  
  1.1      date: 2007/04/18 21:07:52;  author: rawb;  state: Exp;jbosside/core/plugins/org.jboss.ide.eclipse.archives.core/src/main/org/jboss/ide/eclipse/archives/core/model/internal/ArchiveNodeDeltaImpl.java
  
  Index: ArchiveNodeDeltaImpl.java
  ===================================================================
  package org.jboss.ide.eclipse.archives.core.model.internal;
  
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.Iterator;
  
  import org.jboss.ide.eclipse.archives.core.model.IArchiveNode;
  import org.jboss.ide.eclipse.archives.core.model.IArchiveNodeDelta;
  
  public class ArchiveNodeDeltaImpl implements IArchiveNodeDelta {
  	
  	private ArchiveNodeDeltaImpl parentDelta;
  	private ArchiveNodeImpl postNode, preNode;
  	private HashMap attributes, properties, children;
  	private int kind;
  	private IArchiveNodeDelta[] childrenDeltas;
  	
  	/**
  	 * Primary constructor
  	 * @param parentDelta
  	 * @param impl
  	 * @param attributeChanges
  	 * @param propertyChanges
  	 * @param childChanges
  	 */
  	public ArchiveNodeDeltaImpl(ArchiveNodeDeltaImpl parentDelta, ArchiveNodeImpl impl, 
  			HashMap attributeChanges, HashMap propertyChanges, HashMap childChanges) {
  		this.parentDelta = parentDelta;
  		postNode = impl;
  		kind = 0;
  		properties = propertyChanges;
  		attributes = attributeChanges; 
  		children = childChanges;
  		
  		// These three lines adjust my "kind" to be accurate
  		ensureAccurateKind();
  		
  		// create *my* pre-node
  		// this creates an accurate "old" node but without ANY children at all.
  		// The children are expected to be added in the getAffectedChildren
  		preNode = ArchiveDeltaPreNodeFactory.createNode(parentDelta, postNode, attributeChanges, propertyChanges);
  		
  		getAffectedChildren();
  	}
  	
  	/**
  	 * Constructor that forces a child to be added or removed, as judged by the parent
  	 * @param parentDelta
  	 * @param impl
  	 * @param forcedKind
  	 * @param attributeChanges
  	 * @param propertyChanges
  	 * @param childChanges
  	 */
  	public ArchiveNodeDeltaImpl(ArchiveNodeDeltaImpl parentDelta, ArchiveNodeImpl impl, 
  			int forcedKind, HashMap attributeChanges, 
  			HashMap propertyChanges, HashMap childChanges) {
  		this(parentDelta, impl, attributeChanges, propertyChanges, childChanges);
  		kind = kind | forcedKind; // pre-gaming 
  	}
  	
  	/** 
  	 * Get the parent delta
  	 * @return
  	 */
  	protected ArchiveNodeDeltaImpl getParentDelta() {
  		return parentDelta;
  	}
  	
  	protected void ensureAccurateKind() {
  		
  		// Properties First
  		Object key;
  		NodeDelta val;
  		for( Iterator i = properties.keySet().iterator(); i.hasNext(); ) {
  			key = i.next();
  			val = (NodeDelta)properties.get(key);
  			kind = kind | val.getKind();
  		}
  		
  		// Attributes Second
  		if( attributes.keySet().size() > 0 )
  			kind = kind | ATTRIBUTE_CHANGED;
  
  		/*
  		 * Children third.
  		 * 
  		 * The changed children are saved in a hashmap
  		 * Node -> Integer  (where int is one of 
  		 * IPackagesModelDelta.CHILD_ADDED or
  		 * IPackagesModelDelta.CHILD_REMOVED 
  		 */
  		Integer val2;
  		for( Iterator i = children.keySet().iterator(); i.hasNext(); ) {
  			key = i.next();
  			val2 = (Integer)children.get(key);
  			if( val2 != null )
  				kind = kind | val2.intValue();
  		}
  	}
  	
  	
  	// Forced during constructor, will set the flag for CHILD_CHANGED if a child has changed at all.
  	public IArchiveNodeDelta[] getAffectedChildren() {
  		ArrayList priorChildren = new ArrayList();
  		if( childrenDeltas == null ) {
  			
  			// first add the deltas for things that are currently our children
  			// this includes items that haven't been changed, and items that were added
  			IArchiveNode[] children = postNode.getAllChildren();
  			IArchiveNodeDelta delta;
  			ArrayList deltas = new ArrayList();
  			for( int i = 0; i < children.length; i++ ) {
  				// create our child delta before evaluating whether or not to add it
  				delta = getDelta(children[i]);
  				if( delta.getKind() != IArchiveNodeDelta.NO_CHANGE ) {
  					deltas.add(delta);
  					kind = kind | DESCENDENT_CHANGED;
  				}
  
  				// add ALL current nodes, then later remove the added ones
  				priorChildren.add(delta.getPreNode());
  			}
  			
  			// now handle the removed ones
  			ArchiveNodeImpl node;
  			for(Iterator i = this.children.keySet().iterator(); i.hasNext(); ) {
  				node = (ArchiveNodeImpl)i.next();
  				int v = ((Integer)this.children.get(node)).intValue();
  				delta = getDelta(node);
  				if( v == IArchiveNodeDelta.CHILD_REMOVED) {
  					deltas.add(delta);
  					priorChildren.add(delta.getPreNode());
  				} else if( v == IArchiveNodeDelta.CHILD_ADDED) {
  					priorChildren.remove(delta.getPreNode());
  				}
  			}
  			
  			if( preNode != null ) {
  				// now we've got our list of current children... set them. 
  				for( Iterator i = priorChildren.iterator(); i.hasNext(); ) {
  					preNode.addChild((IArchiveNode)i.next());
  				}
  				// now clear pre-node's deltas so it looks shiny
  				preNode.clearDeltas();
  			}
  			
  			childrenDeltas = (IArchiveNodeDelta[]) deltas.toArray(new IArchiveNodeDelta[deltas.size()]);
  		}
  		return childrenDeltas;
  	}
  
  	/*
  	 * Because a node can be ADDED with respect to one node, and
  	 * REMOVED with respect to another, that portion of the delta 
  	 * kind must be set here, from the parent, rather than in the 
  	 * child. 
  	 */
  	private IArchiveNodeDelta getDelta(IArchiveNode child) {
  		if( child instanceof ArchiveNodeImpl ) {
  			int addedOrRemoved = 0;
  			if( children.containsKey(child)) {
  				addedOrRemoved = ((Integer)children.get(child)).intValue() >> 8;
  			}
  			ArchiveNodeImpl impl = (ArchiveNodeImpl)child;
  			
  			// Using a different delta constructor here to force 
  			// whether this child is added or removed. 
  			return new ArchiveNodeDeltaImpl(this, impl, addedOrRemoved,
  					(HashMap)impl.attributeChanges.clone(), 
  					(HashMap)impl.propertyChanges.clone(), 
  					(HashMap)impl.childChanges.clone());
  
  		}
  		
  		return child.getDelta();
  	}
  	
  	public int getKind() {
  		return kind;
  	}
  
  	public IArchiveNode getPostNode() {
  		return postNode;
  	}
  
  	public IArchiveNode getPreNode() {
  		return preNode;
  	}
  
  	public String[] getAttributesWithDeltas() {
  		Collection atts = attributes.keySet();
  		return (String[]) atts.toArray(new String[atts.size()]);
  	}
  
  	public INodeDelta getAttributeDelta(String key) {
  		return (INodeDelta)attributes.get(key);
  	}
  
  	public String[] getPropertiesWithDeltas() {
  		Collection atts = properties.keySet();
  		return (String[]) atts.toArray(new String[atts.size()]);
  	}
  
  	public INodeDelta getPropertyDelta(String key) {
  		return (INodeDelta)properties.get(key);
  	}
  
  	public IArchiveNodeDelta[] getAddedChildrenDeltas() {
  		return getChangedChildren(IArchiveNodeDelta.ADDED);
  	}
  	public IArchiveNodeDelta[] getRemovedChildrenDeltas() {
  		return getChangedChildren(IArchiveNodeDelta.REMOVED);
  	}
  
  	private IArchiveNodeDelta[] getChangedChildren(int type) {
  		ArrayList list = new ArrayList();
  		for( int i = 0; i < childrenDeltas.length; i++ ) {
  			if( (childrenDeltas[i].getKind() & type) != 0 ) {
  				list.add(childrenDeltas[i]);
  			}
  		}
  		return (IArchiveNodeDelta[]) list.toArray(new IArchiveNodeDelta[list.size()]);
  	}
  	
  	/**
  	 * A quick and dirty class to keep track of changing
  	 * values between saves in a model. 
  	 * Used for property changes and attribute changes
  	 * @author rstryker
  	 *
  	 */
  	protected static class NodeDelta implements INodeDelta {
  		private int kind;
  		private Object before, after;
  		public NodeDelta(Object before, Object after, int kind) {
  			this.before = before;
  			this.after = after;
  			this.kind = kind;
  		}
  		public Object getBefore() { return before; }
  		public Object getAfter() { return after; }
  		public int getKind() {
  			return kind;
  		}
  	}
  }
  
  
  
  1.1      date: 2007/04/18 21:07:52;  author: rawb;  state: Exp;jbosside/core/plugins/org.jboss.ide.eclipse.archives.core/src/main/org/jboss/ide/eclipse/archives/core/model/internal/ArchiveDeltaPreNodeFactory.java
  
  Index: ArchiveDeltaPreNodeFactory.java
  ===================================================================
  package org.jboss.ide.eclipse.archives.core.model.internal;
  
  import java.util.HashMap;
  import java.util.Iterator;
  
  import org.jboss.ide.eclipse.archives.core.model.IArchive;
  import org.jboss.ide.eclipse.archives.core.model.IArchiveFileSet;
  import org.jboss.ide.eclipse.archives.core.model.IArchiveFolder;
  import org.jboss.ide.eclipse.archives.core.model.IArchiveNode;
  import org.jboss.ide.eclipse.archives.core.model.internal.ArchiveNodeDeltaImpl.NodeDelta;
  import org.jboss.ide.eclipse.archives.core.model.internal.xb.XbFileSet;
  import org.jboss.ide.eclipse.archives.core.model.internal.xb.XbFolder;
  import org.jboss.ide.eclipse.archives.core.model.internal.xb.XbPackage;
  import org.jboss.ide.eclipse.archives.core.model.internal.xb.XbPackageNodeWithProperties;
  
  
  /**
   * This class generates a replica of what an archive 
   * node looked like before the changes that inspired
   * the delta.
   * 
   * @author rstryker
   *
   */
  public class ArchiveDeltaPreNodeFactory {
  	
  	// children get added later
  	public static ArchiveNodeImpl createNode(ArchiveNodeDeltaImpl parentDelta, ArchiveNodeImpl postChange, 
  			HashMap attributeChanges, HashMap propertyChanges) {
  		
  		switch(postChange.getNodeType()) {
  		case IArchiveNode.TYPE_ARCHIVE_FILESET:
  			XbFileSet fs = createFileset((ArchiveFileSetImpl)postChange, attributeChanges, propertyChanges); 
  			return new DeltaFileset(fs, parentDelta);
  		case IArchiveNode.TYPE_ARCHIVE_FOLDER:
  			XbFolder folder = createFolder((ArchiveFolderImpl)postChange, attributeChanges, propertyChanges);
  			return new DeltaFolder(folder, parentDelta);
  		case IArchiveNode.TYPE_ARCHIVE:
  			XbPackage pack = createPackage((ArchiveImpl)postChange, attributeChanges, propertyChanges);
  			return new DeltaArchive(pack, parentDelta);
  		}
  		
  		return null;
  	}
  	
  	
  	protected static XbFileSet createFileset(ArchiveFileSetImpl postChange,HashMap attributeChanges, HashMap propertyChanges ) {
  		XbFileSet fs = new XbFileSet((XbFileSet)postChange.nodeDelegate);
  //		fs.setDir("FILESET TEST CHANGE");
  		if( attributeChanges.containsKey(IArchiveFileSet.INCLUDES_ATTRIBUTE))
  			fs.setIncludes(getBeforeString(attributeChanges, IArchiveFileSet.INCLUDES_ATTRIBUTE));
  		if( attributeChanges.containsKey(IArchiveFileSet.EXCLUDES_ATTRIBUTE))
  			fs.setExcludes(getBeforeString(attributeChanges, IArchiveFileSet.EXCLUDES_ATTRIBUTE));
  		if( attributeChanges.containsKey(IArchiveFileSet.SOURCE_PATH_ATTRIBUTE))
  			fs.setDir(getBeforeString(attributeChanges, IArchiveFileSet.SOURCE_PATH_ATTRIBUTE));
  		if( attributeChanges.containsKey(IArchiveFileSet.IN_WORKSPACE_ATTRIBUTE))
  			fs.setInWorkspace(getBeforeBoolean(attributeChanges, IArchiveFileSet.IN_WORKSPACE_ATTRIBUTE));
  
  		undoPropertyChanges(fs, propertyChanges);
  		return fs;
  	}
  	
  	protected static XbFolder createFolder(ArchiveFolderImpl postChange,HashMap attributeChanges, HashMap propertyChanges ) {
  		XbFolder folder = new XbFolder((XbFolder)postChange.nodeDelegate);
  		if( attributeChanges.containsKey(IArchiveFolder.NAME_ATTRIBUTE))
  			folder.setName(getBeforeString(attributeChanges, IArchiveFolder.NAME_ATTRIBUTE));
  		undoPropertyChanges(folder, propertyChanges);
  		return folder;
  	}
  	
  	protected static XbPackage createPackage(ArchiveImpl postChange,HashMap attributeChanges, HashMap propertyChanges ) {
  		XbPackage pack = new XbPackage((XbPackage)postChange.nodeDelegate);
  		if( attributeChanges.containsKey(IArchive.NAME_ATTRIBUTE))
  			pack.setName(getBeforeString(attributeChanges, IArchive.NAME_ATTRIBUTE));
  		if( attributeChanges.containsKey(IArchive.PACKAGE_TYPE_ATTRIBUTE))
  			pack.setPackageType(getBeforeString(attributeChanges, IArchive.PACKAGE_TYPE_ATTRIBUTE));
  		if( attributeChanges.containsKey(IArchive.DESTINATION_ATTRIBUTE))
  			pack.setToDir(getBeforeString(attributeChanges, IArchive.DESTINATION_ATTRIBUTE));
  		if( attributeChanges.containsKey(IArchive.IN_WORKSPACE_ATTRIBUTE))
  			pack.setInWorkspace(getBeforeBoolean(attributeChanges, IArchive.IN_WORKSPACE_ATTRIBUTE));
  		if( attributeChanges.containsKey(IArchive.EXPLODED_ATTRIBUTE))
  			pack.setExploded(getBeforeBoolean(attributeChanges, IArchive.EXPLODED_ATTRIBUTE));
  		undoPropertyChanges(pack, propertyChanges);
  		return pack;
  	}
  	
  	protected static boolean getBeforeBoolean(HashMap map, String key) {
  		NodeDelta delta = (NodeDelta)map.get(key);
  		if( delta != null ) {
  			return ((Boolean)delta.getBefore()).booleanValue();
  		}
  		return true;
  	}
  	protected static String getBeforeString(HashMap map, String key) {
  		NodeDelta delta = (NodeDelta)map.get(key);
  		if( delta != null ) {
  			return (String)delta.getBefore();
  		}
  		return null;
  	}
  	
  	// set the properties here to what they were before the delta
  	protected static void undoPropertyChanges(XbPackageNodeWithProperties node, HashMap changes) {
  		String key;
  		NodeDelta val;
  		for( Iterator i = changes.keySet().iterator(); i.hasNext(); ) {
  			key = (String) i.next();
  			val = (NodeDelta)changes.get(key);
  			if( val.getBefore() == null ) {
  				node.getProperties().getProperties().remove(key);
  			} else {
  				node.getProperties().getProperties().setProperty(key, (String)val.getBefore());
  			}
  		}
  
  	}
  	
  	
  	public static class DeltaFileset extends ArchiveFileSetImpl {
  		// everything goes through the delegate or the parent. Simple
  		private ArchiveNodeDeltaImpl parentDelta; 
  		public DeltaFileset(XbFileSet fileset, ArchiveNodeDeltaImpl parentDelta){
  			super(fileset);
  			this.parentDelta = parentDelta;
  		}
  		public IArchiveNode getParent() {
  			return parentDelta == null ? null : parentDelta.getPreNode();
  		}
  	}
  	
  	public static class DeltaFolder extends ArchiveFolderImpl {
  		private ArchiveNodeDeltaImpl parentDelta; 
  		public DeltaFolder(XbFolder folder, ArchiveNodeDeltaImpl parentDelta){
  			super(folder);
  			this.parentDelta = parentDelta;
  		}
  		public IArchiveNode getParent() {
  			return parentDelta == null ? null : parentDelta.getPreNode();
  		}
  	}
  	
  	public static class DeltaArchive extends ArchiveImpl {
  		private ArchiveNodeDeltaImpl parentDelta; 
  		public DeltaArchive(XbPackage pack, ArchiveNodeDeltaImpl parentDelta){
  			super(pack);
  			this.parentDelta = parentDelta;
  		}
  		public IArchiveNode getParent() {
  			return parentDelta == null ? null : parentDelta.getPreNode();
  		}
  	}
  }
  
  
  
  1.1      date: 2007/04/18 21:07:52;  author: rawb;  state: Exp;jbosside/core/plugins/org.jboss.ide.eclipse.archives.core/src/main/org/jboss/ide/eclipse/archives/core/model/internal/ArchiveFileSetImpl.java
  
  Index: ArchiveFileSetImpl.java
  ===================================================================
  /*
   * JBoss, a division of Red Hat
   * Copyright 2006, Red Hat Middleware, LLC, and individual contributors as indicated
   * by the @authors tag. See the copyright.txt in the distribution for a
   * full listing of individual contributors.
   *
   * This 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.1 of
   * the License, or (at your option) any later version.
   *
   * This software 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 software; if not, write to the Free
   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   */
  package org.jboss.ide.eclipse.archives.core.model.internal;
  
  import java.util.ArrayList;
  
  import org.eclipse.core.resources.IFile;
  import org.eclipse.core.resources.ResourcesPlugin;
  import org.eclipse.core.runtime.Assert;
  import org.eclipse.core.runtime.IPath;
  import org.eclipse.core.runtime.Path;
  import org.jboss.ide.eclipse.archives.core.model.DirectoryScannerFactory;
  import org.jboss.ide.eclipse.archives.core.model.IArchiveFileSet;
  import org.jboss.ide.eclipse.archives.core.model.DirectoryScannerFactory.DirectoryScannerExtension;
  import org.jboss.ide.eclipse.archives.core.model.internal.xb.XbFileSet;
  
  /**
   * A PackageFileSetImpl.
   */
  public class ArchiveFileSetImpl extends ArchiveNodeImpl implements
  		IArchiveFileSet {
  
  	private XbFileSet filesetDelegate;
  	private DirectoryScannerExtension scanner;
  	private boolean rescanRequired = true;
  	
  	public ArchiveFileSetImpl() {
  		this(new XbFileSet());
  	}
  	
  	public ArchiveFileSetImpl (XbFileSet delegate) {
  		super(delegate);
  		this.filesetDelegate = delegate;
  	}
  	
  	public IPath[] findMatchingPaths () {
  		DirectoryScannerExtension scanner = getScanner();
  		ArrayList paths = new ArrayList();
  		IPath sp = getGlobalSourcePath();
  		String matched[] = scanner.getIncludedFiles();
  		for (int i = 0; i < matched.length; i++) {
  			IPath path = sp.append(new Path(matched[i]));
  			paths.add(path);
  		}
  		
  		return (IPath[])paths.toArray(new IPath[paths.size()]);
  	}
  	
  	public String getExcludesPattern() {
  		return filesetDelegate.getExcludes();
  	}
  	
  	public boolean isInWorkspace() {
  		return filesetDelegate.isInWorkspace();
  	}
  	
  	public String getIncludesPattern() {
  		return filesetDelegate.getIncludes();
  	}
  
  	// returns a file-system relative path
  	public IPath getGlobalSourcePath() {
  		String path = filesetDelegate.getDir();
  		if (path == null || path.equals(".") || path.equals("")) {
  			return getProject() == null ? null : getProject().getLocation();
  		} else if( isInWorkspace()){
  			return ResourcesPlugin.getWorkspace().getRoot().getLocation().append(path);
  		} else {
  			return new Path(path);
  		}
  	}
  	
  	public IPath getSourcePath() {
  		return new Path(filesetDelegate.getDir());
  	}
  	
  	public boolean matchesFile(IFile file) {
  		return matchesFile(getScanner(), file);
  	}
  
  	public boolean matchesFile(DirectoryScannerExtension scanner, IFile file) {
  		return matchesPath(file.getLocation());
  	}
  	
  	public boolean matchesPath(IPath path) {
  		return matchesPath(getScanner(), path);
  	}
  
  	public boolean matchesPath(DirectoryScannerExtension scanner, IPath path) {
  		if( getGlobalSourcePath().isPrefixOf(path)) {
  			String s = path.toOSString().substring(getGlobalSourcePath().toOSString().length()+1);
  			return scanner.isIncluded(s);
  		}
  		return false;
  	}
  	
  	private synchronized DirectoryScannerExtension getScanner() {
  		if( scanner == null || rescanRequired) {
  			rescanRequired = false;
  			scanner = DirectoryScannerFactory.createDirectoryScanner(
  					getGlobalSourcePath(), getIncludesPattern(), getExcludesPattern(), true);
  		}
  		return scanner;
  	}
  		
  	public int getNodeType() {
  		return TYPE_ARCHIVE_FILESET;
  	}
  	
  	public void setExcludesPattern(String excludes) {
  		attributeChanged(EXCLUDES_ATTRIBUTE, getExcludesPattern(), excludes);
  		filesetDelegate.setExcludes(excludes);
  	}
  
  	public void setIncludesPattern(String includes) {
  		attributeChanged(INCLUDES_ATTRIBUTE, getIncludesPattern(), includes);
  		filesetDelegate.setIncludes(includes);
  	}
  
  	public void setInWorkspace(boolean isInWorkspace) {
  		attributeChanged(IN_WORKSPACE_ATTRIBUTE, new Boolean(isInWorkspace()), new Boolean(isInWorkspace));
  		filesetDelegate.setInWorkspace(isInWorkspace);
  	}
  	
  	public void setSourcePath (IPath path) {
  		Assert.isNotNull(path);
  		IPath src = getGlobalSourcePath();
  		attributeChanged(SOURCE_PATH_ATTRIBUTE, src == null ? null : src.toString(), path == null ? null : path.toString());
  		filesetDelegate.setDir(path.toString());
  	}
  	
  	protected XbFileSet getFileSetDelegate () {
  		return filesetDelegate;
  	}
  
  	// filesets have no path of their own
  	// and should not be the parents of any other node
  	// so the parent is their base location
  	public IPath getRootArchiveRelativePath() {
  		return getParent().getRootArchiveRelativePath(); 
  	}
  	
  	public IPath getRootArchiveRelativePath(IPath inputFile) {
  		if( matchesPath(inputFile)) {
  			String s = inputFile.toOSString().substring(getGlobalSourcePath().toOSString().length()+1);
  			return getParent().getRootArchiveRelativePath().append(s);
  		}
  		return null;
  	}
  
  	public void resetScanner() {
  		rescanRequired = true;
  	}
  }
  
  
  
  1.1      date: 2007/04/18 21:07:52;  author: rawb;  state: Exp;jbosside/core/plugins/org.jboss.ide.eclipse.archives.core/src/main/org/jboss/ide/eclipse/archives/core/model/internal/ArchiveImpl.java
  
  Index: ArchiveImpl.java
  ===================================================================
  /*
   * JBoss, a division of Red Hat
   * Copyright 2006, Red Hat Middleware, LLC, and individual contributors as indicated
   * by the @authors tag. See the copyright.txt in the distribution for a
   * full listing of individual contributors.
   *
   * This 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.1 of
   * the License, or (at your option) any later version.
   *
   * This software 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 software; if not, write to the Free
   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   */
  package org.jboss.ide.eclipse.archives.core.model.internal;
  
  import org.eclipse.core.resources.ResourcesPlugin;
  import org.eclipse.core.runtime.IPath;
  import org.eclipse.core.runtime.Path;
  import org.jboss.ide.eclipse.archives.core.ExtensionManager;
  import org.jboss.ide.eclipse.archives.core.model.IArchive;
  import org.jboss.ide.eclipse.archives.core.model.IArchiveFileSet;
  import org.jboss.ide.eclipse.archives.core.model.IArchiveFolder;
  import org.jboss.ide.eclipse.archives.core.model.IArchiveNode;
  import org.jboss.ide.eclipse.archives.core.model.internal.xb.XbPackage;
  import org.jboss.ide.eclipse.archives.core.model.internal.xb.XbPackages;
  import org.jboss.ide.eclipse.archives.core.model.types.IArchiveType;
  
  /**
   * A Package.
   * 
   * @author Rob stryker
   */
  public class ArchiveImpl extends ArchiveNodeImpl implements IArchive {
  
  	private XbPackage packageDelegate;
  	
  	public ArchiveImpl() {
  		this(new XbPackage());
  	}
  	public ArchiveImpl(XbPackage delegate) {
  		super(delegate);
  		this.packageDelegate = delegate;
  	}
  	
  	public int getNodeType() {
  		return TYPE_ARCHIVE;
  	}
  
  	public boolean isDestinationInWorkspace() {
  		return packageDelegate.isInWorkspace();
  	}
  	
  	public IPath getDestinationPath () {
  		if (packageDelegate.getToDir() == null || packageDelegate.getToDir().equals("."))
  			return getProject() == null ? null : getProject().getLocation();
  		
  		if (isDestinationInWorkspace()) {	
  			return ResourcesPlugin.getWorkspace().getRoot().getLocation().append(new Path(packageDelegate.getToDir()));
  		} else 
  			return new Path(packageDelegate.getToDir());
  	}
  
  	public IPath getArchiveFilePath() {
  		return getDestinationPath().append(getName());
  	}
  	
  	public IArchiveFileSet[] getFileSets() {
  		IArchiveNode nodes[] = getChildren(TYPE_ARCHIVE_FILESET);
  		IArchiveFileSet filesets[] = new IArchiveFileSet[nodes.length];
  		System.arraycopy(nodes, 0, filesets, 0, nodes.length);
  		return filesets;
  	}
  
  	public IArchiveFolder[] getFolders() {
  		IArchiveNode nodes[] = getChildren(TYPE_ARCHIVE_FOLDER);
  		IArchiveFolder folders[] = new IArchiveFolder[nodes.length];
  		System.arraycopy(nodes, 0, folders, 0, nodes.length);
  		return folders;
  	}
  
  	public IArchive[] getArchives() {
  		IArchiveNode nodes[] = getChildren(TYPE_ARCHIVE);
  		IArchive pkgs[] = new IArchive[nodes.length];
  		System.arraycopy(nodes, 0, pkgs, 0, nodes.length);
  		return pkgs;
  	}
  
  	public String getName() {
  		return packageDelegate.getName();
  	}
  
  	public IArchiveType  getArchiveType() {
  		return ExtensionManager.getArchiveType(packageDelegate.getPackageType());
  	}
  		
  	public boolean isExploded() {
  		return packageDelegate.isExploded();
  	}
  	
  	public boolean isTopLevel() {
  		return (packageDelegate.getParent() instanceof XbPackages);
  	}
  	
  	public void addFileSet(IArchiveFileSet fileset) {
  		addChild(fileset);
  	}
  
  	public void addFolder(IArchiveFolder folder) {
  		addChild(folder);
  	}
  
  	public void addPackage(IArchive pkg) {
  		addChild(pkg);
  	}
  
  	public void setDestinationPath(IPath path, boolean inWorkspace) {
  		IPath destPath = getDestinationPath();
  		attributeChanged(IN_WORKSPACE_ATTRIBUTE, new Boolean(isDestinationInWorkspace()), new Boolean(inWorkspace));
  		attributeChanged(DESTINATION_ATTRIBUTE, destPath == null ? null : destPath.toString(), path == null ? null : path.toString());
  		packageDelegate.setInWorkspace(inWorkspace);
  		packageDelegate.setToDir(path.toString());
  	}
  
  	public void setExploded(boolean exploded) {
  		attributeChanged(EXPLODED_ATTRIBUTE, new Boolean(isExploded()), new Boolean(exploded));
  		packageDelegate.setExploded(exploded);
  	}
  
  	public void setName(String name) {
  		attributeChanged(NAME_ATTRIBUTE, getName(), name);
  		packageDelegate.setName(name);
  	}
  
  	public void setArchiveType(IArchiveType type) {
  		attributeChanged(PACKAGE_TYPE_ATTRIBUTE, getArchiveTypeId(), type == null ? null : type.getId());
  		packageDelegate.setPackageType(type.getId());
  	}
  	
  	protected XbPackage getPackageDelegate () {
  		return packageDelegate;
  	}
  
  	public void setArchiveType(String type) {
  		attributeChanged(PACKAGE_TYPE_ATTRIBUTE, getArchiveTypeId(), type);
  		packageDelegate.setPackageType(type);
  	}
  	
  	public String toString() {
  		return getName();
  	}
  	public String getArchiveTypeId() {
  		return packageDelegate.getPackageType();
  	}
  	public IPath getRootArchiveRelativePath() {
  		if( getParent() == null || getParent().getRootArchiveRelativePath() == null )
  			return new Path(getName());
  		return getParent().getRootArchiveRelativePath().append(getName());
  	}
  
  }
  
  
  
  1.1      date: 2007/04/18 21:07:52;  author: rawb;  state: Exp;jbosside/core/plugins/org.jboss.ide.eclipse.archives.core/src/main/org/jboss/ide/eclipse/archives/core/model/internal/ArchiveModelNode.java
  
  Index: ArchiveModelNode.java
  ===================================================================
  package org.jboss.ide.eclipse.archives.core.model.internal;
  
  import org.eclipse.core.resources.IProject;
  import org.eclipse.core.runtime.IPath;
  import org.jboss.ide.eclipse.archives.core.model.IArchive;
  import org.jboss.ide.eclipse.archives.core.model.IArchiveNode;
  import org.jboss.ide.eclipse.archives.core.model.internal.xb.XbPackageNodeWithProperties;
  import org.jboss.ide.eclipse.archives.core.model.internal.xb.XbPackages;
  
  public class ArchiveModelNode extends ArchiveNodeImpl {
  	private IProject project;
  
  	public ArchiveModelNode(IProject project, XbPackageNodeWithProperties node) {
  		super(node);
  		this.project = project;
  	}
  	
  	public IProject getProject() {
  		return project;
  	}
  	
  	public XbPackages getXbPackages() {
  		return (XbPackages)nodeDelegate;
  	}
  	
  	// Can only add packages types here
  	public void addChild(IArchiveNode child) {
  		if( child instanceof IArchive ) {
  			super.addChild(child);
  		}
  	}
  
  	public int getNodeType() {
  		return IArchiveNode.TYPE_MODEL;
  	}
  
  	public IArchiveNode getRoot() {
  		return this;
  	}
  	
  	public boolean connectedToModel() {
  		return ArchivesModel.instance().containsRoot(this);
  	}
  
  	public IArchiveNode getParent() {
  		return null;
  	}
  
  	public void setParent(IArchiveNode parent) {
  	}
  
  	public IPath getRootArchiveRelativePath() {
  		return null;
  	}
  
  	public IPath[] getPackagePaths() {
  		return null;
  	}
  }
  
  
  
  1.1      date: 2007/04/18 21:07:52;  author: rawb;  state: Exp;jbosside/core/plugins/org.jboss.ide.eclipse.archives.core/src/main/org/jboss/ide/eclipse/archives/core/model/internal/ArchivesModel.java
  
  Index: ArchivesModel.java
  ===================================================================
  package org.jboss.ide.eclipse.archives.core.model.internal;
  
  import java.io.ByteArrayInputStream;
  import java.io.ByteArrayOutputStream;
  import java.io.IOException;
  import java.io.OutputStreamWriter;
  import java.util.Arrays;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.List;
  
  import org.eclipse.core.resources.IFile;
  import org.eclipse.core.resources.IProject;
  import org.eclipse.core.resources.IProjectDescription;
  import org.eclipse.core.runtime.CoreException;
  import org.eclipse.core.runtime.IProgressMonitor;
  import org.eclipse.core.runtime.NullProgressMonitor;
  import org.jboss.ide.eclipse.archives.core.Trace;
  import org.jboss.ide.eclipse.archives.core.build.ArchivesNature;
  import org.jboss.ide.eclipse.archives.core.model.IArchive;
  import org.jboss.ide.eclipse.archives.core.model.IArchiveNode;
  import org.jboss.ide.eclipse.archives.core.model.IArchiveNodeDelta;
  import org.jboss.ide.eclipse.archives.core.model.IArchiveNodeVisitor;
  import org.jboss.ide.eclipse.archives.core.model.events.EventManager;
  import org.jboss.ide.eclipse.archives.core.model.internal.xb.XMLBinding;
  import org.jboss.ide.eclipse.archives.core.model.internal.xb.XbFileSet;
  import org.jboss.ide.eclipse.archives.core.model.internal.xb.XbFolder;
  import org.jboss.ide.eclipse.archives.core.model.internal.xb.XbPackage;
  import org.jboss.ide.eclipse.archives.core.model.internal.xb.XbPackageNode;
  import org.jboss.ide.eclipse.archives.core.model.internal.xb.XbPackages;
  
  public class ArchivesModel {
  	
  	public static final String PROJECT_PACKAGES_FILE = ".packages";
  	
  	/**
  	 * Singleton instance
  	 */
  	protected static ArchivesModel instance;
  	public static ArchivesModel instance() {
  		if( instance == null ) 
  			instance = new ArchivesModel();
  		return instance;
  	}
  	
  	private HashMap xbPackages; // maps an IProject to XbPackages
  	private HashMap archivesRoot; // maps an IProject to PackageModelNode, aka root
  	public ArchivesModel() {
  		xbPackages = new HashMap();
  		archivesRoot = new HashMap();
  	}
  	
  	public XbPackages getXbPackages(IProject project) {
  		return (XbPackages)(xbPackages.get(project));
  	}
  	
  	/**
  	 * If the project hasn't been registered, register it
  	 * @param project
  	 * @param monitor
  	 * @return
  	 */
  	public XbPackages getXbPackages(IProject project, IProgressMonitor monitor) {
  		if( !xbPackages.containsKey(project)) 
  			registerProject(project, monitor);
  		return (XbPackages)(xbPackages.get(project));
  	}
  	
  	public boolean accept(IArchiveNodeVisitor visitor) {
  		IArchiveNode children[] = getAllArchives();
  		boolean keepGoing = true;
  
  		if (keepGoing) {
  			for (int i = 0; i < children.length; i++) {
  				if (keepGoing) {
  					keepGoing = children[i].accept(visitor);
  				}
  			}
  		}
  		
  		return keepGoing;
  	}	
  	
  	/**
  	 * Gets every single registered model
  	 * @return
  	 */
  	protected ArchiveModelNode[] getAllArchives() {
  		ArchiveModelNode[] ret = new ArchiveModelNode[archivesRoot.keySet().size()];
  		Iterator i = archivesRoot.keySet().iterator();
  		int x = 0;
  		while(i.hasNext()) {
  			ret[x++] = (ArchiveModelNode)archivesRoot.get(i.next());
  		}
  		return ret;
  	}
  	
  	public ArchiveModelNode getRoot(IProject project) {
  		return getRoot(project, false, new NullProgressMonitor());
  	}
  	
  	public ArchiveModelNode getRoot(IProject project, boolean force, IProgressMonitor monitor) {
  		if( archivesRoot.get(project) == null && force ) {
  			registerProject(project, monitor);
  		}
  		return (ArchiveModelNode)(archivesRoot.get(project));
  	}
  	
  	public IArchive[] getProjectArchives(IProject project) {
  		ArchiveModelNode root = getRoot(project);
  		if( root != null ) {
  			List list = Arrays.asList( getRoot(project).getAllChildren());
  			return (IArchive[]) list.toArray(new IArchive[list.size()]);
  		} else {
  			return null;
  		}
  	}
  	
  	// to make sure the node root is actually in the model
  	public boolean containsRoot(ArchiveModelNode node) {
  		return archivesRoot.containsValue(node);
  	}
  	
  	public void registerProject(IProject project, IProgressMonitor monitor) {
  		// if the file exists, read it in
  		
  		monitor.beginTask("Loading configuration...", XMLBinding.NUM_UNMARSHAL_MONITOR_STEPS + 2);
  		
  		try {
  			if (!project.hasNature(ArchivesNature.NATURE_ID)) {
  				addProjectNature(project, ArchivesNature.NATURE_ID);
  			}
  		} catch (CoreException e) {
  			Trace.trace(getClass(), e);
  		}
  		
  		ArchiveModelNode root;
  		IFile packagesFile = project.getFile(PROJECT_PACKAGES_FILE);
  		if (packagesFile.exists())
  		{
  			try {
  				XbPackages packages = XMLBinding.unmarshal(packagesFile.getContents(), monitor);
  				monitor.worked(1);
  				
  				if (packages == null) {
  					// Empty / non-working XML file loaded
  					Trace.trace(getClass(), "WARNING: .packages file for project " + project.getName() + " is empty or contains the wrong content");
  					return;
  				}
  				root = new ArchiveModelNode(project, packages);
  				xbPackages.put(project, packages);
  				archivesRoot.put(project, root);
  				createPackageNodeImpl(project, packages, null);
  				root.clearDeltas();
  				monitor.worked(1);
  			} catch (CoreException e) {
  				Trace.trace(getClass(), e);
  			}
  		} else {
  			// file not found, just create some default xbpackages and insert them
  			XbPackages packages = new XbPackages();
  			xbPackages.put(project, packages);
  			archivesRoot.put(project, new ArchiveModelNode(project, packages));
  		}
  	}
  	
  	protected ArchiveNodeImpl createPackageNodeImpl (IProject project, XbPackageNode node, IArchiveNode parent) {
  		
  		if( node instanceof XbPackages ) {
  			ArchiveModelNode impl = getRoot(project);
  			for (Iterator iter = node.getAllChildren().iterator(); iter.hasNext(); ) {
  				XbPackageNode child = (XbPackageNode) iter.next();
  				ArchiveNodeImpl childImpl = createPackageNodeImpl(project, child, impl);
  				if (impl != null && childImpl != null) {
  					impl.addChild(childImpl, false);
  				}
  			}
  			return null;
  		}
  		
  		ArchiveNodeImpl nodeImpl = null;
  		if (node instanceof XbPackage) {
  			nodeImpl = new ArchiveImpl((XbPackage)node);
  		} else if (node instanceof XbFolder) {
  			nodeImpl = new ArchiveFolderImpl((XbFolder)node);
  		} else if (node instanceof XbFileSet) {
  			nodeImpl = new ArchiveFileSetImpl((XbFileSet)node);
  		}
  		
  		for (Iterator iter = node.getAllChildren().iterator(); iter.hasNext(); ) {
  			XbPackageNode child = (XbPackageNode) iter.next();
  			ArchiveNodeImpl childImpl = createPackageNodeImpl(project, child, nodeImpl);
  			if (nodeImpl != null && childImpl != null) {
  				nodeImpl.addChild(childImpl, false);
  			}
  		}
  		
  		return nodeImpl;
  	}
  	
     public static boolean addProjectNature(IProject project, String natureId) {
  	   boolean added = false;
  	   try {
  		   if (project != null && natureId != null) {
  			   IProjectDescription desc = project.getDescription();
  			   
  			   if (!project.hasNature(natureId)) {
  				   String natureIds[] = desc.getNatureIds();
  				   String newNatureIds[] = new String[natureIds.length + 1];
  				   
  				   System.arraycopy(natureIds, 0, newNatureIds, 1, natureIds.length);
  				   newNatureIds[0] = natureId;
  				   desc.setNatureIds(newNatureIds);
  				   
  				   project.getProject().setDescription(desc, new NullProgressMonitor());
  				   added = true;
  			   }
  		   }
  	   } catch (CoreException e) {
  		   e.printStackTrace();
  	   }
  	   return added;
     }
  
  	public void saveModel (IProject project, IProgressMonitor monitor) {
  		// get a list of dirty nodes
  		
  		try {
  			if (monitor == null)
  				monitor = new NullProgressMonitor();
  			
  			ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
  			OutputStreamWriter writer = new OutputStreamWriter(bytesOut);
  			XbPackages packs = getXbPackages(project);
  			XMLBinding.marshal(packs, writer, monitor);
  			writer.close();
  			
  			ByteArrayInputStream bytesIn = new ByteArrayInputStream(bytesOut.toByteArray());
  			IFile packagesFile = project.getFile(ArchivesModel.PROJECT_PACKAGES_FILE);
  			if (!packagesFile.exists())
  				packagesFile.create(bytesIn, true, monitor);
  			else
  				packagesFile.setContents(bytesIn, true, true, monitor);
  			
  			bytesIn.close();
  			bytesOut.close();
  			
  			if (!project.hasNature(ArchivesNature.NATURE_ID)) {
  				addProjectNature(project, ArchivesNature.NATURE_ID);
  			}
  			
  			// get deltas
  			try {
  				ArchiveModelNode root = getRoot(project);
  				IArchiveNodeDelta delta = root.getDelta();
  				
  				// clear deltas
  				root.clearDeltas();
  				
  				// fire delta events
  				EventManager.fireDelta(delta);
  			} catch( Exception e ) {
  				e.printStackTrace();
  			}
  		} catch (IOException e) {
  			// TODO Auto-generated catch block
  			e.printStackTrace();
  		} catch (CoreException e) {
  			// TODO Auto-generated catch block
  			e.printStackTrace();
  		}
  	}
  	
  	public void attach(IArchiveNode parent, IArchiveNode child, IProgressMonitor monitor) {
  		parent.addChild(child);
  		if( parent.connectedToModel() && parent.getProject() != null) {
  			// save
  			saveModel(parent.getProject(), monitor);
  		}
  	}
  }
  
  
  
  1.1      date: 2007/04/18 21:07:52;  author: rawb;  state: Exp;jbosside/core/plugins/org.jboss.ide.eclipse.archives.core/src/main/org/jboss/ide/eclipse/archives/core/model/internal/ArchiveNodeImpl.java
  
  Index: ArchiveNodeImpl.java
  ===================================================================
  /*
   * JBoss, a division of Red Hat
   * Copyright 2006, Red Hat Middleware, LLC, and individual contributors as indicated
   * by the @authors tag. See the copyright.txt in the distribution for a
   * full listing of individual contributors.
   *
   * This 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.1 of
   * the License, or (at your option) any later version.
   *
   * This software 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 software; if not, write to the Free
   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   */
  package org.jboss.ide.eclipse.archives.core.model.internal;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Properties;
  
  import org.eclipse.core.resources.IProject;
  import org.eclipse.core.runtime.Assert;
  import org.jboss.ide.eclipse.archives.core.model.IArchive;
  import org.jboss.ide.eclipse.archives.core.model.IArchiveNode;
  import org.jboss.ide.eclipse.archives.core.model.IArchiveNodeDelta;
  import org.jboss.ide.eclipse.archives.core.model.IArchiveNodeVisitor;
  import org.jboss.ide.eclipse.archives.core.model.internal.ArchiveNodeDeltaImpl.NodeDelta;
  import org.jboss.ide.eclipse.archives.core.model.internal.xb.XbPackageNode;
  import org.jboss.ide.eclipse.archives.core.model.internal.xb.XbPackageNodeWithProperties;
  import org.jboss.ide.eclipse.archives.core.model.internal.xb.XbPackages;
  
  public abstract class ArchiveNodeImpl implements IArchiveNode {
  
  	protected XbPackageNodeWithProperties nodeDelegate;
  	protected IArchiveNode parent;
  	protected ArrayList children;
  	
  	// cached data
  	protected HashMap attributeChanges;
  	protected HashMap propertyChanges;
  	protected HashMap childChanges;
  	
  	
  	public ArchiveNodeImpl (XbPackageNodeWithProperties delegate) {
  		nodeDelegate = delegate;
  		children = new ArrayList();
  
  		// for deltas
  		attributeChanges = new HashMap();
  		propertyChanges = new HashMap();
  		childChanges = new HashMap();
  	}
  		
  	public XbPackageNode getNodeDelegate() {
  		return nodeDelegate;
  	}
  	
  	public IArchiveNode getRoot() {
  		return parent == null ? this : parent.getRoot();
  	}
  	
  	public IArchive getRootArchive() {
  		IArchiveNode parent = this.parent;
  		IArchive topArchives = null;
  
  		if( getNodeType() == IArchiveNode.TYPE_ARCHIVE ) topArchives = (IArchive)this;
  		while( parent != null ) {
  			if( parent.getNodeType() == IArchiveNode.TYPE_ARCHIVE ) 
  				topArchives = (IArchive)parent;
  			parent = parent.getParent();
  		}
  		return topArchives;
  	}
  
  	
  	public IArchiveNode[] getAllChildren () {
  		return (IArchiveNode[]) children.toArray(new IArchiveNode[children.size()]);
  	}
  	
  	public IArchiveNode[] getChildren(int type) {
  		ArrayList typedChildren = new ArrayList();
  		for (Iterator iter = children.iterator(); iter.hasNext(); ) {
  			IArchiveNode child = (IArchiveNode) iter.next();
  			if (child.getNodeType() == type) {
  				typedChildren.add(child);
  			}
  		}
  		
  		return (IArchiveNode[]) typedChildren.toArray(new IArchiveNode[typedChildren.size()]);
  	}
  	
  	public boolean hasChildren () {
  		return nodeDelegate.hasChildren();
  	}
  	
  	public boolean hasChild (IArchiveNode child) {
  		ArchiveNodeImpl childImpl = (ArchiveNodeImpl)child;
  		return nodeDelegate.getAllChildren().contains(childImpl.nodeDelegate);
  	}
  
  	public IArchiveNode getParent() {
  		return parent;
  	}
  
  	public void setParent (IArchiveNode parent) {
  		if( getParent() != null && parent != getParent()) {
  			getParent().removeChild(this);
  		}
  		
  		if (parent != null && !(parent instanceof ArchiveModelNode)) {
  			this.parent = parent;
  			nodeDelegate.setParent(((ArchiveNodeImpl)parent).getNodeDelegate());
  		} else if (getNodeType() == TYPE_ARCHIVE) {
  			this.parent = parent;
  			XbPackages packages = ArchivesModel.instance().getXbPackages(getProject());
  			nodeDelegate.setParent(packages);
  		}
  	}
  	
  	public IProject getProject() {
  		IArchiveNode root = getRoot();
  		if( root.getNodeType() != IArchiveNode.TYPE_MODEL)
  			return null;
  		return root.getProject();
  	}
  	
  	public String getProperty(String property) {
  		return getProperties().getProperty(property);
  	}
  	
  	public void setProperty(String property, String value) {
  		if( property == null ) return;
  		propertyChanged(property, getProperty(property), value);
  		if( value == null ) {
  			getProperties().remove(property);
  		} else {
  			getProperties().setProperty(property, value);
  		}
  	}
  
  	public Properties getProperties() {
  		return nodeDelegate.getProperties().getProperties();
  	}
  
  	public boolean accept(IArchiveNodeVisitor visitor) {
  		return accept(visitor, false);
  	}
  	
  	public boolean accept(IArchiveNodeVisitor visitor, boolean depthFirst) {
  		IArchiveNode children[] = getAllChildren();
  		boolean keepGoing = true;
  		
  		if (!depthFirst)
  			keepGoing = visitor.visit(this);
  		
  		if (keepGoing) {
  			for (int i = 0; i < children.length; i++) {
  				if (keepGoing) {
  					keepGoing = children[i].accept(visitor, depthFirst);
  				}
  			}
  		}
  		
  		if (depthFirst && keepGoing)
  			keepGoing = visitor.visit(this);
  		
  		return keepGoing;
  	}
  	
  	public void addChild(IArchiveNode node) {
  		addChild(node, true);
  	}
  
  	public void addChild(IArchiveNode child, boolean addInDelegate) {
  		Assert.isNotNull(child);
  		ArchiveNodeImpl childImpl = (ArchiveNodeImpl) child;
  		children.add(childImpl);
  		childImpl.setParent(this);
  		if( addInDelegate )
  			nodeDelegate.addChild(childImpl.nodeDelegate);
  		childChanges(child, IArchiveNodeDelta.CHILD_ADDED);
  	}
  
  	public void removeChild(IArchiveNode node) {
  		Assert.isNotNull(node);
  		ArchiveNodeImpl impl = (ArchiveNodeImpl) node;
  		boolean removed = false;
  		if (nodeDelegate.getAllChildren().contains(impl.nodeDelegate)) {
  			nodeDelegate.removeChild(impl.nodeDelegate);
  			removed = true;
  		}
  
  		if (children.contains(node)) {
  			children.remove(node);
  			removed = true;
  		}
  		if( removed )
  			childChanges(node, IArchiveNodeDelta.CHILD_REMOVED);
  	}
  	
  	public Object getAdapter(Class adapter) {
  		if (adapter.equals(IProject.class)) {
  			return getProject();
  		} else if (adapter.equals(IArchiveNode.class)) {
  			return this;
  		}
  		else return null;
  	}
  	
  
  	public boolean connectedToModel() {
  		IArchiveNode root = getRoot();
  		return root instanceof ArchiveModelNode && ArchivesModel.instance().containsRoot((ArchiveModelNode)root);
  	}
  	
  	
  	/*
  	 * The following are for deltas. It keeps track of recent changes
  	 * and makes sure all changes are accoutned for properly between saves
  	 */
  	protected void attributeChanged(String key, Object beforeValue, Object afterValue) {
  		int kind = IArchiveNodeDelta.ATTRIBUTE_CHANGED;
  		HashMap map = attributeChanges;
  		
  		// short circuit if no change has REALLY occurred
  		if( beforeValue != null && beforeValue.equals(afterValue)) return;
  		
  		if( map.containsKey(key)) {
  			Object original = ((NodeDelta)map.get(key)).getBefore();
  			if( original == null && afterValue == null ) 
  				map.remove(key);
  			else if( original == null ) 
  				map.put(key, new NodeDelta(original, afterValue, kind));
  			else if( original.equals(afterValue))
  				// value was changed from x to y, then back to x. Therefore, no change
  				map.remove(key);
  			else
  				// value was changed from x to y to z. 
  				// Before should remain x, after should become z
  				map.put(key, new NodeDelta(original, afterValue, kind));
  		} else {
  			// added
  			map.put(key, new NodeDelta(beforeValue, afterValue, kind));
  		}
  	}
  	
  	protected void propertyChanged(String key, Object beforeValue, Object afterValue) {
  		HashMap changeMap = propertyChanges;
  		// short circuit if no change has REALLY occurred
  		if( beforeValue != null && beforeValue.equals(afterValue)) return;
  		
  		
  		if( changeMap.containsKey(key)) {
  			// element has already been added, removed, or changed since last save
  			Object original = ((NodeDelta)changeMap.get(key)).getBefore();
  			if( original == null && afterValue == null ) 
  				changeMap.remove(key);
  			else if( original == null ) 
  				changeMap.put(key, new NodeDelta(original, afterValue, IArchiveNodeDelta.PROPERTY_ADDED));
  			else if( original.equals(afterValue))
  				// value was changed from x to y, then back to x. Therefore, no change
  				changeMap.remove(key);
  			else if( afterValue == null ) {
  				// changed from x to y to null, so removed
  				changeMap.put(key, new NodeDelta(original, afterValue, IArchiveNodeDelta.PROPERTY_REMOVED));
  			} else {
  				// changed from x to y to z, so changed
  				changeMap.put(key, new NodeDelta(original, afterValue, IArchiveNodeDelta.PROPERTY_CHANGED));
  			}
  		} else {
  			int kind;
  			if( beforeValue == null ) kind = IArchiveNodeDelta.PROPERTY_ADDED;
  			else if( afterValue == null ) kind = IArchiveNodeDelta.PROPERTY_REMOVED;
  			else kind = IArchiveNodeDelta.PROPERTY_CHANGED;
  			changeMap.put(key, new NodeDelta(beforeValue, afterValue, kind));
  		}
  	}
  	
  	// children are either added or removed here.  
  	// changed children are discovered through the delta
  	protected void childChanges(IArchiveNode node, int changeType) {
  		if( childChanges.containsKey(node)) {
  			int lastChange = ((Integer)childChanges.get(node)).intValue();
  			if( lastChange == IArchiveNodeDelta.CHILD_ADDED && changeType == IArchiveNodeDelta.CHILD_REMOVED) {
  				childChanges.remove(node);
  			} else if( lastChange == IArchiveNodeDelta.CHILD_REMOVED && changeType == IArchiveNodeDelta.CHILD_ADDED) {
  				childChanges.remove(node);
  			}
  		} else {
  			childChanges.put(node, new Integer(changeType));
  		}
  	}	
  	
  	public IArchiveNodeDelta getDelta() {
  		return new ArchiveNodeDeltaImpl(null, this, (HashMap)attributeChanges.clone(), 
  				(HashMap)propertyChanges.clone(), (HashMap)childChanges.clone());
  	}
  	
  	protected void clearDeltas() {
  		attributeChanges.clear();
  		propertyChanges.clear();
  		childChanges.clear();
  		
  		// clear children
  		IArchiveNode[] children = getAllChildren();
  		for( int i = 0; i < children.length; i++ ) 
  			((ArchiveNodeImpl)children[i]).clearDeltas();
  	}
  }
  
  
  



More information about the jboss-cvs-commits mailing list