001: /*
002: *
003: * The DbUnit Database Testing Framework
004: * Copyright (C)2002-2004, DbUnit.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: */
021:
022: package org.dbunit.ant;
023:
024: import org.slf4j.Logger;
025: import org.slf4j.LoggerFactory;
026:
027: import java.util.*;
028: import java.util.ArrayList;
029: import java.util.List;
030:
031: import org.apache.tools.ant.BuildException;
032: import org.apache.tools.ant.types.FilterSet;
033:
034: /**
035: * This element is a container for Queries. It facilitates reuse
036: * through references. Using Ant 1.6 and greater, references can be
037: * defined in a single build file and <i>import</i>ed into many others.
038: * An example of where this is useful follows:
039: * <p>
040: * In our database
041: * we have INDIVIDUALS which must have an associated NAME_INFO and
042: * at least one IND_ADDRESS. The developer creating a dataset for
043: * his/her tests probably won't know all the details of what relationships are
044: * expected, and if he did, its an error prone and repetitive task
045: * to create the correct SQL for entities in each dataset.
046: * Missing a related table, not only creates invalid data for your tests,
047: * but also is likely to cause DBUnit setUp() failures due to foreign key
048: * constraint errors.
049: * (ex. If a previous test had inserted INDIVIDUALS
050: * and NAME_INFO and my test tries to delete only the INDIVIDUALS, the
051: * NAME_INFO.IND_ID constraint would prevent it)
052: * <p>
053: * Usage:
054: *
055: * <pre>
056: * <!-- ======== Define the reusable reference ========== -->
057: *
058: * <queryset id="individuals">
059: * <query name="INDIVIDUALS" sql="
060: * SELECT * FROM APS_DATA.INDIVIDUALS WHERE IND_ID IN (@subQuery@)"/>
061: *
062: * <query name="NAME_INFO" sql="
063: * SELECT B.* FROM APS_DATA.INDIVIDUALS A, APS_DATA.NAME_INFO B
064: * WHERE A.IND_ID IN (@subQuery@)
065: * AND B.IND_ID = A.IND_ID"/>
066: *
067: * <query name="IND_ADDRESSES" sql="
068: * SELECT B.* FROM APS_DATA.INDIVIDUALS A, APS_DATA.IND_ADDRESSES B
069: * WHERE A.IND_ID IN (@subQuery@)
070: * AND B.IND_ID = A.IND_ID"/>
071: * </queryset>
072: *
073: * <!-- ========= Use the reference ====================== -->
074: *
075: * <dbunit dest="@{destDir}" driver="${jdbcDriver}"
076: * url="${jdbcURL}" userid="${jdbcUser}" password="${jdbcPassword}">
077: * <export dest="someDir">
078: * <queryset refid="individuals">
079: * <filterset>
080: * <filter token="subQuery" value="
081: * SELECT IND_ID FROM APS_DATA.INDIVIDUALS WHERE USER_NAME = 'UNKNOWN'"/>
082: * </filterset>
083: * </queryset>
084: *
085: * <queryset>
086: * <query name="MAN_EVENT_TYPE"
087: * sql="SELECT * FROM MANUSCRIPTS.MAN_EVENT_TYPE"/>
088: * <query name="JOURNAL" sql="SELECT * FROM MANUSCRIPTS.JOURNAL"/>
089: * </queryset>
090: * </export>
091: * </dbunit>
092: *
093: * </pre>
094: *
095: * @author Lenny Marks lenny@aps.org
096: * @version $Revision: 554 $
097: * @since Sep. 13 2004
098: */
099: public class QuerySet {
100:
101: /**
102: * Logger for this class
103: */
104: private static final Logger logger = LoggerFactory
105: .getLogger(QuerySet.class);
106:
107: private String id;
108: private String refid;
109: private List queries = new ArrayList();
110: private List filterSets = new ArrayList();
111:
112: private static String ERR_MSG = "Cannot specify 'id' and 'refid' attributes together in queryset.";
113:
114: public QuerySet() {
115: super ();
116: }
117:
118: public void addQuery(Query query) {
119: logger.debug("addQuery(query=" + query + ") - start");
120:
121: queries.add(query);
122: }
123:
124: public void addFilterSet(FilterSet filterSet) {
125: logger.debug("addFilterSet(filterSet=" + filterSet
126: + ") - start");
127:
128: filterSets.add(filterSet);
129: }
130:
131: public String getId() {
132: logger.debug("getId() - start");
133:
134: return id;
135: }
136:
137: public String getRefid() {
138: logger.debug("getRefid() - start");
139:
140: return refid;
141: }
142:
143: public void setId(String string) {
144: logger.debug("setId(string=" + string + ") - start");
145:
146: if (refid != null)
147: throw new BuildException(ERR_MSG);
148: id = string;
149: }
150:
151: public void setRefid(String string) {
152: logger.debug("setRefid(string=" + string + ") - start");
153:
154: if (id != null)
155: throw new BuildException(ERR_MSG);
156: refid = string;
157: }
158:
159: protected List getQueries() {
160: logger.debug("getQueries() - start");
161:
162: Iterator i = queries.iterator();
163: while (i.hasNext()) {
164: Query query = (Query) i.next();
165: replaceTokens(query);
166: }
167:
168: return queries;
169:
170: }
171:
172: private void replaceTokens(Query query) {
173: logger.debug("replaceTokens(query=" + query + ") - start");
174:
175: Iterator i = filterSets.iterator();
176: while (i.hasNext()) {
177: FilterSet filterSet = (FilterSet) i.next();
178: query.setSql(filterSet.replaceTokens(query.getSql()));
179: }
180: }
181:
182: public void copyQueriesFrom(QuerySet referenced) {
183: logger.debug("copyQueriesFrom(referenced=" + referenced
184: + ") - start");
185:
186: Iterator i = referenced.queries.iterator();
187: while (i.hasNext()) {
188: addQuery((Query) i.next());
189: }
190: }
191:
192: }
|