001: /*
002: * ====================================================================
003: * JAFFA - Java Application Framework For All
004: *
005: * Copyright (C) 2002 JAFFA Development Group
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: *
021: * Redistribution and use of this software and associated documentation ("Software"),
022: * with or without modification, are permitted provided that the following conditions are met:
023: * 1. Redistributions of source code must retain copyright statements and notices.
024: * Redistributions must also contain a copy of this document.
025: * 2. Redistributions in binary form must reproduce the above copyright notice,
026: * this list of conditions and the following disclaimer in the documentation
027: * and/or other materials provided with the distribution.
028: * 3. The name "JAFFA" must not be used to endorse or promote products derived from
029: * this Software without prior written permission. For written permission,
030: * please contact mail to: jaffagroup@yahoo.com.
031: * 4. Products derived from this Software may not be called "JAFFA" nor may "JAFFA"
032: * appear in their names without prior written permission.
033: * 5. Due credit should be given to the JAFFA Project (http://jaffa.sourceforge.net).
034: *
035: * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: */
049:
050: /*
051: * DataTypeMapping.java
052: *
053: * Created on February 18, 2004, 6:14 PM
054: */
055:
056: package org.jaffa.beans.moulding.mapping;
057:
058: import java.lang.reflect.Constructor;
059: import java.lang.reflect.Method;
060: import java.util.Calendar;
061: import java.util.Date;
062: import java.util.HashMap;
063: import java.util.Iterator;
064: import java.util.Map;
065: import org.apache.log4j.Logger;
066: import org.jaffa.datatypes.DateOnly;
067: import org.jaffa.datatypes.DateTime;
068:
069: /**
070: *
071: * @author PaulE
072: */
073: public class DataTypeMapping {
074: private static Logger log = Logger.getLogger(DataTypeMapping.class);
075: /*
076: interchange - with no data loss
077: DateOnly -> DateTime
078: DateTime -> Long, Calander, Date
079: Character -> Short, String
080: Short -> Integer
081: Integer -> Long
082: Float -> Double
083: Boolean -> String
084: interchange - with possible data loss
085: DateTime -> DateOnly
086: Long -> Integer
087: Integer -> Short
088: String -> Boolean, Long, DateTime, Double
089: Double -> Float
090: */
091:
092: /** This is a map where the key is a Class object that is mappable
093: * each entry is a Map, where the key is a Class that indicates what
094: * class it is mappable to, and the value is the method to use for the
095: * translation
096: */
097: private static Map mapping = new HashMap();
098:
099: static {
100: Map m;
101: Method method;
102: Constructor cons;
103: try {
104: //---------------------------------------------------------------
105: // Set up tranlators for a source of org.jaffa.datatypes.DateTime
106: m = new HashMap();
107: //---------------------
108: // convert to a Calander
109: method = DateTime.class.getMethod("getCalendar",
110: new Class[] {});
111: m.put(Calendar.class, method);
112: //---------------------
113: // convert to a Date
114: method = DateTime.class.getMethod("getUtilDate",
115: new Class[] {});
116: m.put(Date.class, method);
117: //---------------------
118: mapping.put(DateTime.class, m);
119:
120: //---------------------------------------------------------------
121: // Set up tranlators for a source of org.jaffa.datatypes.DateOnly
122: m = new HashMap();
123: //---------------------
124: // convert to a Calander
125: method = DateOnly.class.getMethod("getCalendar",
126: new Class[] {});
127: m.put(Calendar.class, method);
128: //---------------------
129: // convert to a Date
130: method = DateOnly.class.getMethod("getUtilDate",
131: new Class[] {});
132: m.put(Date.class, method);
133: //---------------------
134: // convert to a DateTime
135: method = DateOnly.class.getMethod("toDateTime",
136: new Class[] { DateOnly.class });
137: m.put(DateTime.class, method);
138: //---------------------
139: mapping.put(DateOnly.class, m);
140:
141: //---------------------------------------------------------------
142: // Set up tranlators for a source of java.util.Calander
143: m = new HashMap();
144: //---------------------
145: // convert to a DateTime
146: cons = DateTime.class
147: .getConstructor(new Class[] { Calendar.class });
148: m.put(DateTime.class, cons);
149: //---------------------
150: // convert to a DateTime
151: cons = DateOnly.class
152: .getConstructor(new Class[] { Calendar.class });
153: m.put(DateOnly.class, cons);
154: //---------------------
155: mapping.put(Calendar.class, m);
156:
157: //---------------------------------------------------------------
158: // Set up tranlators for a source of java.util.Date
159: m = new HashMap();
160: //---------------------
161: // convert to a DateTime
162: cons = DateTime.class
163: .getConstructor(new Class[] { Date.class });
164: m.put(DateTime.class, cons);
165: //---------------------
166: // convert to a DateTime
167: cons = DateOnly.class
168: .getConstructor(new Class[] { Date.class });
169: m.put(DateOnly.class, cons);
170: //---------------------
171: mapping.put(Date.class, m);
172:
173: } catch (NoSuchMethodException e) {
174: log
175: .error(
176: "Problem findTarget(m, target)initializing data type mappings",
177: e);
178: throw new NoSuchMethodError(e.getMessage());
179: }
180: }
181:
182: public static boolean isMappable(Class source, Class target) {
183: Map m = findSource(source);
184: return (m != null && findTarget(m, target) != null);
185: }
186:
187: /** Creates a new instance of DataTypeMapping */
188: public static Object map(Object source, Class target)
189: throws ClassCastException {
190: // Map null straight back!
191: if (source == null)
192: return null;
193:
194: try {
195: log.debug("Looking for source class: " + source.getClass());
196: Map m = findSource(source.getClass());
197: if (m == null)
198: throw new ClassCastException(
199: "Class is not a mappable - no translation exists");
200: log.debug("Looking for target translator: " + target);
201: Object translator = findTarget(m, target);
202: if (translator == null)
203: throw new ClassCastException(
204: "Class can't be mapped - null translator");
205: if (translator instanceof Method) {
206: Method me = (Method) translator;
207: if (me.getParameterTypes() == null
208: || me.getParameterTypes().length == 0)
209: // no imputs
210: return me.invoke(source, new Object[] {});
211: else
212: // assume static with source as input
213: return me.invoke(null, new Object[] { source });
214: } else if (translator instanceof Constructor) {
215: Constructor con = (Constructor) translator;
216: return con.newInstance(new Object[] { source });
217: } else
218: throw new ClassCastException(
219: "Class can't be mapped - unknown translator");
220: } catch (ClassCastException e) {
221: throw e;
222: } catch (Exception e) {
223: if (e instanceof ClassCastException)
224: throw (ClassCastException) e;
225: log.error("Problem during mapping. Source="
226: + source.getClass() + ", Target=" + target, e);
227: throw new ClassCastException("Problem during mapping");
228: }
229: }
230:
231: private static Map findSource(Class source) {
232: if (mapping.containsKey(source))
233: return (Map) mapping.get(source);
234: // Loop through all source objects to see if there is baseclass
235: for (Iterator i = mapping.keySet().iterator(); i.hasNext();) {
236: Class s = (Class) i.next();
237: if (s.isAssignableFrom(source))
238: return (Map) mapping.get(s);
239: }
240: log.debug("Can't find source mapping for " + source);
241: return null;
242: }
243:
244: private static Object findTarget(Map methods, Class target) {
245: if (methods.containsKey(target))
246: return methods.get(target);
247: // Loop through all source objects to see if there is baseclass
248: for (Iterator i = methods.keySet().iterator(); i.hasNext();) {
249: Class s = (Class) i.next();
250: if (target.isAssignableFrom(s))
251: return (Map) methods.get(s);
252: }
253: log.debug("Can't find target mapping for " + target);
254: return null;
255: }
256:
257: }
|