001: /**
002: * Copyright (C) 2006 NetMind Consulting Bt.
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 3 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */package hu.netmind.persistence;
018:
019: import java.util.HashMap;
020: import java.util.Map;
021: import java.util.List;
022: import java.util.Vector;
023: import java.util.Iterator;
024: import java.lang.reflect.Method;
025: import org.apache.log4j.Logger;
026: import java.util.Date;
027:
028: /**
029: * Information and transformations on a given class.
030: * @author Brautigam Robert
031: * @version Revision: $Revision$
032: */
033: public class StrictDynamicHandler extends StrictStaticHandler {
034: private static Logger logger = Logger
035: .getLogger(StrictDynamicHandler.class);
036:
037: private HashMap attributeNames;
038: private HashMap originalAttributes;
039:
040: StrictDynamicHandler(StoreContext context, ClassEntry sourceEntry) {
041: // Init static attributes
042: super (context, sourceEntry);
043: // Init dynamic attributes additionally
044: try {
045: // Init
046: attributeNames = new HashMap();
047: // Add this class' attribute to sets
048: originalAttributes = new HashMap(
049: getPersistenceAttributeTypes(sourceEntry
050: .getSourceClass(), sourceEntry
051: .getDynamicName()));
052: Iterator nameIterator = originalAttributes.keySet()
053: .iterator();
054: while (nameIterator.hasNext()) {
055: String attributeName = ((String) nameIterator.next());
056: attributeTypes.put(attributeName.toLowerCase(),
057: originalAttributes.get(attributeName));
058: attributeNames.put(attributeName.toLowerCase(),
059: attributeName);
060: }
061: } catch (Throwable e) {
062: throw new StoreException(
063: "can not instantiate dynamic class info: "
064: + sourceEntry, e);
065: }
066: }
067:
068: /**
069: * Get the dynamic attributes types of an object.
070: * @return The dynamic types map, or null, if object is not dynamic.
071: */
072: public static Map getPersistenceAttributeTypes(Class clazz,
073: String dynamicName) {
074: Method method = null;
075: Class current = clazz;
076: while ((current != null) && (method == null)) {
077: try {
078: method = current.getDeclaredMethod(
079: "getPersistenceAttributeTypes", new Class[] {
080: Class.class, String.class });
081: } catch (NoSuchMethodException e) {
082: // No problem
083: }
084: current = current.getSuperclass();
085: }
086: if (method == null) {
087: logger.debug("dyanmic attributes method not found in '"
088: + clazz + ":" + dynamicName + "'");
089: return null; // If no such method, then this has no dynamic attrs
090: }
091: try {
092: Map result = (Map) method.invoke(null, new Object[] {
093: clazz, dynamicName });
094: if (logger.isDebugEnabled())
095: logger.debug("determined dynamic attributes for '"
096: + clazz + ":" + dynamicName + "': " + result);
097: return result;
098: } catch (Exception e) {
099: throw new StoreException(
100: "error while getting dynamic attribute types", e);
101: }
102: }
103:
104: /**
105: * Determine whether object schema has changed.
106: */
107: public boolean hasChanged() {
108: return !originalAttributes.equals(getPersistenceAttributeTypes(
109: sourceEntry.getSourceClass(), sourceEntry
110: .getDynamicName()));
111: }
112:
113: /**
114: * Get the attribute value from a given object of this class and
115: * from given attribute.
116: */
117: public Object getAttributeValue(Object obj, String attributeName) {
118: if (isStatic(attributeName))
119: return super .getAttributeValue(obj, attributeName);
120: return ((Map) obj).get(((String) attributeNames
121: .get(attributeName.toLowerCase())));
122: }
123:
124: /**
125: * Set an object as value into object given.
126: */
127: public void setAttributeValue(Object obj, String attributeName,
128: Object value) {
129: // Handle static attribute
130: if (isStatic(attributeName)) {
131: super .setAttributeValue(obj, attributeName, value);
132: return;
133: }
134: // Handle dynamic attributes now
135: Class attrClass = (Class) attributeTypes.get(attributeName
136: .toLowerCase());
137: if (attrClass == null)
138: return;
139: Class valueClass = null;
140: Map map = (Map) obj;
141: // Convert name to real name
142: attributeName = (String) attributeNames.get(attributeName
143: .toLowerCase());
144: // Check if value is null. Remove the key, if
145: // the value is null.
146: if (value == null) {
147: map.remove(attributeName);
148: return;
149: }
150: valueClass = value.getClass();
151: // Handle primitive types with exceptional circumstances
152: if ((attrClass.equals(Character.class))
153: || (attrClass.equals(char.class))
154: && (valueClass.equals(String.class))) {
155: if (((String) value).length() > 0)
156: map.put(attributeName, new Character(((String) value)
157: .charAt(0)));
158: }
159: // Byte array
160: else if (attrClass.equals(byte[].class))
161: map.put(attributeName, value);
162: // Boolean
163: else if ((attrClass.equals(Boolean.class) || attrClass
164: .equals(boolean.class))
165: && ((valueClass.equals(Integer.class)) || (valueClass
166: .equals(Long.class)))) {
167: map.put(attributeName, new Boolean(((Number) value)
168: .intValue() > 0));
169: }
170: // Easy primitive classes
171: else if (valueClass.equals(String.class)
172: || valueClass.equals(Date.class)
173: || valueClass.equals(Boolean.class))
174: map.put(attributeName, value);
175: // Container classes
176: else if ((value instanceof Map) || (value instanceof List))
177: map.put(attributeName, value);
178: // Not easy number classes
179: else if (value instanceof Number) {
180: Number number = (Number) value;
181: if (attrClass.equals(Byte.class)
182: || attrClass.equals(byte.class))
183: map.put(attributeName, new Byte(number.byteValue()));
184: if (attrClass.equals(Double.class)
185: || attrClass.equals(double.class))
186: map
187: .put(attributeName, new Double(number
188: .doubleValue()));
189: if (attrClass.equals(Float.class)
190: || attrClass.equals(float.class))
191: map.put(attributeName, new Float(number.floatValue()));
192: if (attrClass.equals(Integer.class)
193: || attrClass.equals(int.class))
194: map.put(attributeName, new Integer(number.intValue()));
195: if (attrClass.equals(Long.class)
196: || attrClass.equals(long.class))
197: map.put(attributeName, new Long(number.longValue()));
198: if (attrClass.equals(Short.class)
199: || attrClass.equals(short.class))
200: map.put(attributeName, new Short(number.shortValue()));
201: }
202: // All other objects
203: else {
204: if ((value != null)
205: || (context.getClassTracker().getType(attrClass) != ClassTracker.TYPE_PRIMITIVE))
206: map.put(attributeName, value);
207: }
208: }
209: }
|