From: <de...@us...> - 2005-10-18 14:43:43
|
Update of /cvsroot/dbunit/dbunit/src/java/org/dbunit/util/search In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30808/src/java/org/dbunit/util/search Added Files: IEdge.java SearchException.java AbstractExcludeNodesSearchCallback.java Edge.java AbstractNodesFilterSearchCallback.java DepthFirstSearch.java ISearchAlgorithm.java AbstractIncludeNodesSearchCallback.java ISearchCallback.java Log Message: Addition of a search api and implementation from Felipe. Updates to dependencies, cleanup of Hypersonic startup/shutdown process. --- NEW FILE: IEdge.java --- /* * * The DbUnit Database Testing Framework * Copyright (C)2005, DbUnit.org * * 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.1 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 * */ package org.dbunit.util.search; /** * A bidirectional edge on the graph to be searched.<br> * It must implement <code>Comparable</code> so the * <code>ISearchCallback</code> can properly order the dependencies of a node * (so, typically, the implementations will compare the <code>getTo()</code> * node). * * @author Felipe Leme <db...@fe...> * @version $Revision: 1.1 $ * @since Aug 25, 2005 */ public interface IEdge extends Comparable { /** * Get the node this edge originates from. * * @return node this edge originates from. */ Object getFrom(); /** * Get the node this edge points to. * * @return node this edge points to. */ Object getTo(); } --- NEW FILE: SearchException.java --- /* * * The DbUnit Database Testing Framework * Copyright (C)2002-2004, DbUnit.org * * 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.1 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 * */ package org.dbunit.util.search; import org.dbunit.DatabaseUnitException; /** * @author Felipe Leme <db...@fe...> * @version $Revision: 1.1 $ * @since Aug 25, 2005 */ public class SearchException extends DatabaseUnitException { /** * */ private static final long serialVersionUID = -8369726048539373231L; public SearchException() { } public SearchException(String msg) { super(msg); } public SearchException(String msg, Throwable e) { super(msg, e); } public SearchException(Throwable e) { super(e); } } --- NEW FILE: AbstractExcludeNodesSearchCallback.java --- /* * * The DbUnit Database Testing Framework * Copyright (C)2005, DbUnit.org * * 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.1 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 * */ package org.dbunit.util.search; import java.util.Set; /** * @author Felipe Leme <db...@fe...> * @version $Revision: 1.1 $ * @since Aug 25, 2005 * */ public abstract class AbstractExcludeNodesSearchCallback extends AbstractNodesFilterSearchCallback { public AbstractExcludeNodesSearchCallback(Set deniedNodes) { super(); setDeniedNodes(deniedNodes); } public AbstractExcludeNodesSearchCallback(Object[] deniedNodes) { super(); setDeniedNodes(deniedNodes); } } --- NEW FILE: Edge.java --- /* * * The DbUnit Database Testing Framework * Copyright (C)2005, DbUnit.org * * 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.1 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 * */ package org.dbunit.util.search; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; /** * Basic implementation of the IEdge interface. * * @author Felipe Leme <db...@fe...> * @version $Revision: 1.1 $ * @since Aug 25, 2005 */ public class Edge implements IEdge { private final Comparable nodeFrom; private final Comparable nodeTo; public Edge(Comparable nodeFrom, Comparable nodeTo) { if (nodeFrom == null) { throw new IllegalArgumentException("node from cannot be null"); } if (nodeTo == null) { throw new IllegalArgumentException("node to cannot be null"); } this.nodeFrom = nodeFrom; this.nodeTo = nodeTo; } public Object getFrom() { return this.nodeFrom; } public Object getTo() { return this.nodeTo; } public String toString() { return this.nodeFrom + "->" + this.nodeTo; } public int compareTo(Object o) { Edge otherEdge = (Edge) o; int result = this.nodeFrom.compareTo(otherEdge.getFrom()); if ( result == 0 ) { result = this.nodeTo.compareTo(otherEdge.getTo()); } return result; } public boolean equals(Object obj) { return EqualsBuilder.reflectionEquals( this, obj ); } public int hashCode() { return HashCodeBuilder.reflectionHashCode(this); } } --- NEW FILE: AbstractNodesFilterSearchCallback.java --- /* * * The DbUnit Database Testing Framework * Copyright (C)2005, DbUnit.org * * 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.1 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 * */ package org.dbunit.util.search; import java.util.HashSet; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Super-class for ISearchCallback implementations that needs to filter which * nodes should be included or excluded from the search.<br> * This class implements the <code>searchNode()</code> based on its internal * mode, which could be <code>ALLOW_MODE</code>, <code>DENY_MODE</code> or * <code>NO_MODE</code>: * <ul> * <li><code>NO_MODE</code> is the default mode and means <code>searchNode()</code> * always return true</li> * <li><code>ALLOW_MODE</code> is set when <code>setAllowedNodes()</code> is called * and it means <code>searchNode()</code> will return true only if the node is * contained on the Set (or array) passed to <code>setAllowedNodes()</code> * <li><code>DENY_MODE</code> is set when <code>setDeniedNodes()</code> is called * and it means <code>searchNode()</code> will return true only if the node is * not contained on the Set (or array) passed to <code>setDeniedNodes()</code> * * @author Felipe Leme <db...@fe...> * @version $Revision: 1.1 $ * @since Aug 25, 2005 * */ public abstract class AbstractNodesFilterSearchCallback implements ISearchCallback { protected final Log logger = LogFactory.getLog(getClass()); // internal modes protected static final int NO_MODE = 0; protected static final int ALLOW_MODE = 1; protected static final int DENY_MODE = 2; private int filteringMode = NO_MODE; private Set filteredNodes = new HashSet(); /** * Default constructor. * */ public AbstractNodesFilterSearchCallback() { } /** * Get which modes are allowed/denied, depending on the operation mode. * @return which modes are allowed/denied, depending on the operation mode. */ protected Set getFilteredNodes() { return this.filteredNodes; } /** * Get the operation mode * @return operation mode */ protected int getFilteringMode() { return this.filteringMode; } /** * Set which modes are allowed on the search. * @param filteredNodes which modes are allowed on the search. */ protected void setAllowedNodes(Set filteredNodes) { setFilteredNodes(filteredNodes); this.filteringMode = ALLOW_MODE; } /** * Set which modes are allowed on the search. * @param filteredNodes which modes are allowed on the search. */ protected void setAllowedNodes(Object[] filteredNodes) { setFilteredNodes(filteredNodes); this.filteringMode = ALLOW_MODE; } /** * Set which modes are not allowed on the search. * @param filteredNodes which modes are not allowed on the search. */ protected void setDeniedNodes(Set filteredNodes) { setFilteredNodes(filteredNodes); this.filteringMode = DENY_MODE; } /** * Set which modes are not allowed on the search. * @param filteredNodes which modes are not allowed on the search. */ protected void setDeniedNodes(Object[] filteredNodes) { setFilteredNodes(filteredNodes); this.filteringMode = DENY_MODE; } /** * Do nothing... */ public void nodeAdded(Object fromNode) throws SearchException { // do nothing } public boolean searchNode(Object node) throws SearchException { switch( this.filteringMode ) { case ALLOW_MODE: return getFilteredNodes().contains(node); case DENY_MODE: return !getFilteredNodes().contains(node); default: return true; } } private void setFilteredNodes(Set filteredNodes) { this.filteredNodes = new HashSet(filteredNodes); } private void setFilteredNodes(Object[] filteredNodes) { this.filteredNodes = new HashSet(filteredNodes.length); for (int i = 0; i < filteredNodes.length; i++) { this.filteredNodes.add(filteredNodes[i]); } } } --- NEW FILE: DepthFirstSearch.java --- /* * * The DbUnit Database Testing Framework * Copyright (C)2005, DbUnit.org * * 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.1 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 * */ package org.dbunit.util.search; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.SortedSet; import org.apache.commons.collections.set.ListOrderedSet; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Search using depth-first algorithm.<br> * <br> * An instance of this class must be used only once, as it maintains the * internal state of the search.<br> * <br> * * @author Felipe Leme <db...@fe...> * @version $Revision: 1.1 $ * @since Aug 25, 2005 * */ public class DepthFirstSearch implements ISearchAlgorithm { // nodes that were already scanned during the search private Set scannedNodes; private Set reverseScannedNodes; protected final Log logger = LogFactory.getLog(getClass()); // result of the search private Set result; // input of the search private Set nodesFrom; // callback used to help the search private ISearchCallback callback; // flag, as one instance cannot be used more than once private boolean searching = false; /** * Helper method, returns a Set from an array of objects. * Note the Iterator returned by this Set mantains the order of the array. * @param objects array of objects * @return Set with the elements of the array */ public static Set objectsToSet( Object[] objects ) { Set set = new ListOrderedSet(); for (int i = 0; i < objects.length; i++) { set.add(objects[i]); } return set; } /** * Helper method, returns an array of Objects from a Set. * @param a Set * @return array of Objects with the elements of the Set */ public static Object[] setToObjects( Set set ) { Object[] objects = new Object[ set.size() ]; int i=0; for (Iterator iter = set.iterator(); iter.hasNext(); i++) { objects[i] = iter.next(); } return objects; } /** * Helper method, returns an array of Strings from a Set. * @param a Set of Strings * @return array of Strings with the elements of the Set */ public static String[] setToStrings( Set set ) { String[] strings = new String[ set.size() ]; int i=0; for (Iterator iter = set.iterator(); iter.hasNext(); i++) { strings[i] = (String) iter.next(); } return strings; } /** * Alternative option to search() that takes an array of nodes as input (instead of a Set) */ public Set search(Object[] nodesFrom, ISearchCallback callback) throws SearchException { return search(objectsToSet(nodesFrom), callback); } /** * @see ISearchAlgorithm */ public Set search(Set nodesFrom, ISearchCallback callback) throws SearchException { synchronized (this) { if (searching) { throw new IllegalStateException("already searching/searched"); } this.searching = true; } // set of tables that will be returned (i.e, the declared tables and its // depedencies) this.result = new ListOrderedSet(); // callback used to help the search this.callback = callback; this.nodesFrom = new ListOrderedSet(); int sizeNodesFromBefore = 0; int sizeResultBefore = 0; boolean keepSearching = true; this.scannedNodes = new HashSet(); this.reverseScannedNodes = new HashSet(); this.scannedNodes = new HashSet(); do { // In a traditional depth-first search, the getEdges() method should return only // edges where this node is the 'from' vertex, as the graph is known in advance. // But in our case, the graph is built 'on the fly', so it's possible that the // getEdges() also returns edges where the node is the 'to' vertex. // So, before we do the "real" search, we need to do a reverse search to find out // all the nodes that should be part of the input. Iterator iterator = nodesFrom.iterator(); while (iterator.hasNext()) { Object node = iterator.next(); reverseSearch(node); } // now that the input is adjusted, do the search iterator = this.nodesFrom.iterator(); while (iterator.hasNext()) { Object node = iterator.next(); search(node); } nodesFrom = new HashSet(this.result); // decides if we continue searching boolean sizesDontMatch = this.result.size() != this.nodesFrom.size(); boolean resultChanged = this.result.size() != sizeResultBefore; boolean nodesFromChanged = this.nodesFrom.size() != sizeNodesFromBefore; sizeNodesFromBefore = this.nodesFrom.size(); sizeResultBefore = this.result.size(); keepSearching = sizesDontMatch && ( resultChanged || nodesFromChanged ); } while ( keepSearching ); return this.result; } /** * This is the real depth first search algorithm, which is called recursively. * * @param node node where the search starts * @return true if the node has been already searched before * @throws Exception if an exception occurs while getting the edges */ private boolean search(Object node) throws SearchException { if ( this.logger.isDebugEnabled() ) { this.logger.debug( "search:" + node ); } if (this.scannedNodes.contains(node)) { if ( this.logger.isDebugEnabled() ) { this.logger.debug( "already searched; returning true" ); } return true; } if (!this.callback.searchNode(node)) { if ( this.logger.isTraceEnabled() ) { this.logger.trace( "Callback handler blocked filtered out node " + node ); } return true; } if ( this.logger.isDebugEnabled() ) { this.logger.debug("Pushing " + node); } this.scannedNodes.add(node); // first, search the nodes the node depends on SortedSet edges = this.callback.getEdges(node); if (edges != null) { Iterator iterator = edges.iterator(); while (iterator.hasNext()) { // and recursively search these nodes IEdge edge = (IEdge) iterator.next(); Object toNode = edge.getTo(); search(toNode); } } // finally, add the node to the result this.logger.trace( "Adding node " + node + " to the final result" ); this.callback.nodeAdded(node); result.add(node); return false; } /** * Do a reverse search (i.e, searching the other way of the edges) in order * to adjust the input before the real search. * @param node node where the search starts * @return true if the node has been already reverse-searched before * @throws Exception if an exception occurs while getting the edges */ private boolean reverseSearch(Object node) throws SearchException { if ( this.logger.isDebugEnabled() ) { this.logger.debug( "reverseSearch:" + node ); } if (this.reverseScannedNodes.contains(node)) { if ( this.logger.isDebugEnabled() ) { this.logger.debug( "already searched; returning true" ); } return true; } if (!this.callback.searchNode(node)) { if ( this.logger.isTraceEnabled() ) { this.logger.trace( "callback handler blocked filtered out node (reverse) " + node ); } return true; } if ( this.logger.isDebugEnabled() ) { this.logger.debug("Pushing (reverse) " + node); } this.reverseScannedNodes.add(node); // first, search the nodes the node depends on SortedSet edges = this.callback.getEdges(node); if (edges != null) { Iterator iterator = edges.iterator(); while (iterator.hasNext()) { // and recursively search these nodes if we find a match IEdge edge = (IEdge) iterator.next(); Object toNode = edge.getTo(); if ( toNode.equals(node) ) { Object fromNode = edge.getFrom(); reverseSearch(fromNode); } } } // finally, add the node to the input this.nodesFrom.add(node); return false; } } --- NEW FILE: ISearchAlgorithm.java --- /* * * The DbUnit Database Testing Framework * Copyright (C)2005, DbUnit.org * * 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.1 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 * */ package org.dbunit.util.search; import java.util.Set; /** * Interface representing an algorithm that searchs a graph. * * @author Felipe Leme <db...@fe...> * @version $Revision: 1.1 $ * @since Aug 25, 2005 * */ public interface ISearchAlgorithm { /** * Search all nodes that originates from a set of nodes. * * @param nodesFrom input nodes * @param callback helper callback * @return all nodes, in the right dependent order (like a LinkedHashSet) * @throws Exception exception wrapper */ Set search(Set nodesFrom, ISearchCallback callback) throws SearchException; } --- NEW FILE: AbstractIncludeNodesSearchCallback.java --- /* * * The DbUnit Database Testing Framework * Copyright (C)2005, DbUnit.org * * 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.1 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 * */ package org.dbunit.util.search; import java.util.Set; /** * @author Felipe Leme <db...@fe...> * @version $Revision: 1.1 $ * @since Aug 25, 2005 * */ public abstract class AbstractIncludeNodesSearchCallback extends AbstractNodesFilterSearchCallback { public AbstractIncludeNodesSearchCallback(Set allowedNodes) { super(); setAllowedNodes(allowedNodes); } public AbstractIncludeNodesSearchCallback(Object[] allowedNodes) { super(); setAllowedNodes(allowedNodes); } } --- NEW FILE: ISearchCallback.java --- /* * * The DbUnit Database Testing Framework * Copyright (C)2005, DbUnit.org * * 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.1 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 * */ package org.dbunit.util.search; import java.util.SortedSet; /** * Callback used by the search algorithms.<br> * This interface is responsible for providing the edges of the graph and it can * be notified of some events generated by the search. * * @author Felipe Leme <db...@fe...> * @version $Revision: 1.1 $ * @since Aug 25, 2005 */ public interface ISearchCallback { /** * Get the edges originating from a node. * * @param node * node from * @return all edges originating from this node. * @throws Exception * exception wrapper */ SortedSet getEdges(Object fromNode) throws SearchException; /** * Notifies the callback that a node has been added to the search result. * * @param fromNode * node that has been added. * @throws Exception * exception wrapper */ void nodeAdded(Object fromNode) throws SearchException; /** * Decides if a node should be searched or not * * @param node * node to be filtered * @return true if the node should be searched * @throws Exception * exception wrapper */ boolean searchNode(Object node) throws SearchException; } |