001: //$Id: DateCreatorAction.java 282 2007-07-19 22:46:27Z jg_hamburg $
002: /********************************************************************************
003: * DDTUnit, a Datadriven Approach to Unit- and Moduletesting
004: * Copyright (c) 2004, Joerg and Kai Gellien
005: * All rights reserved.
006: *
007: * The Software is provided under the terms of the Common Public License 1.0
008: * as provided with the distribution of DDTUnit in the file cpl-v10.html.
009: * Redistribution and use in source and binary forms, with or without
010: * modification, are permitted provided that the following conditions
011: * are met:
012: *
013: * + Redistributions of source code must retain the above copyright
014: * notice, this list of conditions and the following disclaimer.
015: *
016: * + Redistributions in binary form must reproduce the above
017: * copyright notice, this list of conditions and the following
018: * disclaimer in the documentation and/or other materials provided
019: * with the distribution.
020: *
021: * + Neither the id of the authors or DDTUnit, nor the
022: * names of its contributors may be used to endorse or promote
023: * products derived from this software without specific prior
024: * written permission.
025: *
026: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
027: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
028: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
029: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
030: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
031: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
032: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
033: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
034: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
035: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
036: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
037: ********************************************************************************/package junitx.ddtunit.data.processing;
038:
039: import java.text.DateFormat;
040: import java.text.ParseException;
041: import java.text.SimpleDateFormat;
042: import java.util.Calendar;
043: import java.util.Date;
044: import java.util.Locale;
045: import java.util.Map;
046: import java.util.Set;
047:
048: import junitx.ddtunit.DDTException;
049: import junitx.ddtunit.data.DDTTestDataException;
050: import junitx.ddtunit.data.TypedObject;
051: import junitx.ddtunit.util.ClassAnalyser;
052: import junitx.ddtunit.util.DDTConfiguration;
053: import junitx.ddtunit.util.DDTDateFormat;
054:
055: import org.apache.log4j.Logger;
056:
057: /**
058: * This class contains object state and other information to create object from
059: * SAX event stream.
060: *
061: * @author jg
062: */
063: public class DateCreatorAction extends ActionBase {
064: private final static Logger log = Logger
065: .getLogger(DateCreatorAction.class);
066:
067: private final String XML_ATTR_DATEFORMAT = "dateformat";
068:
069: private final String XML_ATTR_DATELOCALE = "locale";
070:
071: /**
072: * special key for actual date only
073: */
074: public final static String SYSDATE = "!SYSDATE!";
075:
076: /**
077: * special key for actual date/time
078: */
079: public final static String SYSTIME = "!SYSTIME!";
080:
081: public static final String DATE_GENERIC = "generic";
082:
083: public static final String DATE_LOCALE = "locale";
084:
085: /**
086: *
087: * Constructor used as standard constructor to instanciate actions of this
088: * type
089: *
090: * @param attrMap
091: */
092: public DateCreatorAction(Map<String, String> attrMap) {
093: super (attrMap);
094: }
095:
096: /*
097: * (non-Javadoc)
098: *
099: * @see junitx.ddtunit.parser.ActionBase#process()
100: */
101: public IAction process() {
102: log.debug("process DateCreator - START");
103: if (!this .successorProcessed) {
104: processNoSuccessor();
105: }
106: IAction rootAction = this .getPrevious();
107: if (rootAction != null) {
108: String hintValue = rootAction.getHint();
109:
110: if (HintTypes.COLLECTION.equals(hintValue)
111: || HintTypes.MAP.equals(hintValue)
112: || HintTypes.ATTRLIST.equals(hintValue)
113: || HintTypes.FIELDS.equals(hintValue)
114: || HintTypes.CONSTRUCTOR.equals(hintValue)
115: || HintTypes.CALL.equals(hintValue)
116: || HintTypes.BEAN.equals(hintValue)
117: || HintTypes.ARRAY.equals(hintValue)
118: || HintTypes.INTERNAL_MAPENTRY.equals(hintValue)) {
119: rootAction.processSuccessor(this );
120: } else {
121: throw new DDTException("Unknown hint (" + hintValue
122: + ")- stop processing.");
123: }
124: } else {
125: if (hasReferenceInfo()) {
126: TypedObject destObject;
127: if (this .attrMap.get(ParserConstants.XML_ATTR_TYPE) == null) {
128: destObject = new TypedObject(getAttribute("refid"));
129: } else {
130: destObject = new TypedObject(getAttribute("refid"),
131: getType());
132: }
133: IReferenceInfo refInfo = new ObjectReferenceInfo(this
134: .getObject(), destObject);
135: add(refInfo);
136: }
137: }
138: this .pop();
139: return this ;
140: }
141:
142: public void processSuccessor(IAction successor) {
143: log.debug("processSuccessor(" + successor + ") - START");
144: // create attribute list action and insert after rootAction
145: if (HintTypes.CONTENT.equals(successor.getHint())) {
146: String content = successor.getValue().toString();
147: if (!ContentCreatorAction.CONTENT_NULL.equals(content)) {
148: String format = (this .getAttribute(XML_ATTR_DATEFORMAT) == null) ? DATE_GENERIC
149: : this .getAttribute(XML_ATTR_DATEFORMAT);
150: String locale = ((this
151: .getAttribute(XML_ATTR_DATELOCALE) == null) ? DATE_LOCALE
152: : this .getAttribute(XML_ATTR_DATELOCALE));
153: Date date = DateFactory.create(this .getType(), content,
154: format, locale);
155: this .setValue(date);
156: }
157: }
158: this .successorProcessed = true;
159: }
160:
161: public void processNoSuccessor() {
162: throw new DDTException(
163: "Specify !NULL! or date. No empty date tag allowed.");
164: }
165:
166: /*
167: * (non-Javadoc)
168: *
169: * @see junitx.ddtunit.parser.ActionBase#inject()
170: */
171: public IAction inject() {
172: String type = (String) this .attrMap
173: .get(ParserConstants.XML_ATTR_TYPE);
174: String id = (String) this .attrMap
175: .get(ParserConstants.XML_ATTR_ID);
176: this .injectedObject = new TypedObject(id, type);
177: return this ;
178: }
179:
180: static class DateFactory {
181: private static Calendar CAL = Calendar.getInstance();
182:
183: private final static DateFormat PROP_SYSDATE = new SimpleDateFormat(
184: "dd.mm.yyyy");
185:
186: private final static DateFormat PROP_SYSTIME = new SimpleDateFormat(
187: "dd.mm.yyyy HH:mm:ss.SSSS");
188:
189: /**
190: * Create Date object
191: *
192: * @param clazz
193: * of Date to create
194: * @param content
195: * representing the date details
196: * @param format
197: * of date provided as String
198: * @param locale
199: * to use for date parsing
200: * @return requested date object or exception on creation error
201: */
202: public static Date create(String clazz, String content,
203: String format, String locale) {
204: Date date = null;
205: checkOnDateAncestor(clazz);
206: if (SYSDATE.equals(content)) {
207: date = CAL.getTime();
208: try {
209: PROP_SYSDATE.parse(PROP_SYSDATE.format(date));
210: } catch (Exception ex) {
211: throw new DDTTestDataException(
212: "Error on creation of actual Date object '"
213: + content + "'", ex);
214: }
215: } else if (SYSTIME.equals(content)) {
216: date = CAL.getTime();
217: } else if (DATE_GENERIC.equals(format)) {
218: Map<String, DDTDateFormat> dateFormatMap = DDTConfiguration
219: .getInstance().getDateMap();
220: boolean errorOnParsing = false;
221: boolean formatFound = false;
222: for (Map.Entry entry : dateFormatMap.entrySet()) {
223: String name = (String) entry.getKey();
224: DDTDateFormat formater = (DDTDateFormat) entry
225: .getValue();
226: try {
227: if (formater.toString().length() == content
228: .length()) {
229: date = formater.parse(content);
230: errorOnParsing = false;
231: formatFound = true;
232: break;
233: }
234: } catch (Exception ex) {
235: log.warn("Error on creation of Date object '"
236: + content + "' by format '" + formater
237: + "'");
238: errorOnParsing = true;
239: }
240: }
241: if (errorOnParsing) {
242: throw new DDTTestDataException(
243: "Error on creation of Date object (format="
244: + format + ", content=" + content
245: + ")");
246: }
247: if (!formatFound) {
248: throw new DDTTestDataException(
249: "Error on creation of Date object, format not found. (format="
250: + format + ", content=" + content
251: + ")");
252: }
253: } else {
254: DDTDateFormat formater = selectDateFormater(format,
255: locale);
256: try {
257: if (formater.toString().length() == content
258: .length()) {
259: date = formater.parse(content);
260: } else {
261: throw new DDTTestDataException(
262: "Date Formater '" + formater
263: + "' does not match '"
264: + content + "'.");
265: }
266: } catch (ParseException ex) {
267: throw new DDTTestDataException(
268: "Error on creation of Date object '"
269: + content + "' by format '"
270: + format + "' and LOCALE '"
271: + locale + "'", ex);
272: }
273: }
274: return date;
275: }
276:
277: /**
278: * @param format
279: * @param locale
280: * @return
281: */
282: private static DDTDateFormat selectDateFormater(String format,
283: String locale) {
284: DDTDateFormat formater;
285: // check for predefined format first
286: Map<String, DDTDateFormat> dateFormatMap = DDTConfiguration
287: .getInstance().getDateMap();
288: if (dateFormatMap.containsKey(format)) {
289: formater = dateFormatMap.get(format);
290: } else {
291: Locale myLocale;
292: if (DATE_LOCALE.equals(locale)) {
293: myLocale = DDTConfiguration.getInstance()
294: .getActiveLocale();
295: } else {
296: String[] details = locale.split("_");
297: if (details.length != 2) {
298: throw new DDTTestDataException(
299: "Provided wrong locale " + locale);
300: }
301: myLocale = new Locale(details[0], details[1]);
302: }
303:
304: formater = new DDTDateFormat(format, myLocale);
305: }
306: return formater;
307: }
308:
309: private static void checkOnDateAncestor(String clazz) {
310: boolean check = false;
311: try {
312: Class checkClazz = Class.forName(clazz);
313: Set super Elements = ClassAnalyser
314: .getSuperElements(checkClazz);
315: check = checkClazz.equals(java.util.Date.class)
316: || super Elements.contains(java.util.Date.class);
317: } catch (Exception ex) {
318: throw new DDTTestDataException("Class " + clazz
319: + " is no ancestor of java.util.Date.", ex);
320: }
321: if (!check) {
322: throw new DDTTestDataException("Class " + clazz
323: + " is no ancestor of java.util.Date.");
324: }
325: }
326:
327: }
328: }
|