001: /*--------------------------------------------------------------------------*
002: | Copyright (C) 2006 Christopher Kohlhaas |
003: | |
004: | This program is free software; you can redistribute it and/or modify |
005: | it under the terms of the GNU General Public License as published by the |
006: | Free Software Foundation. A copy of the license has been included with |
007: | these distribution in the COPYING file, if not go to www.fsf.org |
008: | |
009: | As a special exception, you are granted the permissions to link this |
010: | program with every library, which license fulfills the Open Source |
011: | Definition as published by the Open Source Initiative (OSI). |
012: *--------------------------------------------------------------------------*/
013: package org.rapla.entities.dynamictype.internal;
014:
015: import java.text.ParseException;
016: import java.util.Date;
017: import java.util.HashMap;
018: import java.util.Locale;
019:
020: import org.rapla.components.util.SerializableDateTimeFormat;
021: import org.rapla.components.util.Tools;
022: import org.rapla.entities.Category;
023: import org.rapla.entities.EntityNotFoundException;
024: import org.rapla.entities.IllegalAnnotationException;
025: import org.rapla.entities.MultiLanguageName;
026: import org.rapla.entities.RaplaType;
027: import org.rapla.entities.dynamictype.Attribute;
028: import org.rapla.entities.dynamictype.AttributeType;
029: import org.rapla.entities.dynamictype.ConstraintIds;
030: import org.rapla.entities.dynamictype.DynamicType;
031: import org.rapla.entities.internal.CategoryImpl;
032: import org.rapla.entities.storage.EntityResolver;
033: import org.rapla.entities.storage.Mementable;
034: import org.rapla.entities.storage.RefEntity;
035: import org.rapla.entities.storage.internal.SimpleEntity;
036: import org.rapla.storage.LocalCache;
037:
038: public class AttributeImpl extends SimpleEntity implements Attribute,
039: Mementable, java.io.Serializable {
040: // Don't forget to increase the serialVersionUID when you change the fields
041: private static final long serialVersionUID = 2;
042:
043: private MultiLanguageName name = new MultiLanguageName();
044: private AttributeType type;
045: private String key;
046: private boolean bOptional = false;
047: private HashMap annotations = new HashMap();
048:
049: public final static AttributeType DEFAULT_TYPE = AttributeType.STRING;
050:
051: public AttributeImpl() {
052: this .type = DEFAULT_TYPE;
053: }
054:
055: public AttributeImpl(AttributeType type) {
056: setType(type);
057: }
058:
059: void setParent(DynamicType parent) {
060: getReferenceHandler().put("parent", parent);
061: }
062:
063: public DynamicType getDynamicType() {
064: return (DynamicType) getReferenceHandler().get("parent");
065: }
066:
067: final public RaplaType getRaplaType() {
068: return TYPE;
069: }
070:
071: public AttributeType getType() {
072: return type;
073: }
074:
075: public void setType(AttributeType type) {
076: this .type = type;
077: }
078:
079: public MultiLanguageName getName() {
080: return name;
081: }
082:
083: public void setReadOnly(boolean enable) {
084: super .setReadOnly(enable);
085: name.setReadOnly(enable);
086: }
087:
088: public String getName(Locale locale) {
089: return name.getName(locale.getLanguage());
090: }
091:
092: public String getKey() {
093: return key;
094: }
095:
096: public void setConstraint(String key, Object constraint) {
097: checkWritable();
098: if (getConstraintClass(key) == Category.class) {
099: getReferenceHandler().put("constraint." + key,
100: (Category) constraint);
101: }
102: }
103:
104: public Object getConstraint(String key) {
105: if (getConstraintClass(key) == Category.class) {
106: return getReferenceHandler().get("constraint." + key);
107: }
108: return null;
109: }
110:
111: public Class getConstraintClass(String key) {
112: if (key.equals(ConstraintIds.KEY_ROOT_CATEGORY)) {
113: return Category.class;
114: }
115: return String.class;
116: }
117:
118: public String[] getConstraintKeys() {
119: if (type.equals(AttributeType.CATEGORY)) {
120: return new String[] { ConstraintIds.KEY_ROOT_CATEGORY };
121: } else {
122: return new String[0];
123: }
124: }
125:
126: public void setKey(String key) {
127: checkWritable();
128: this .key = key;
129: }
130:
131: public boolean isValid(Object obj) {
132: return true;
133: }
134:
135: public boolean isOptional() {
136: return bOptional;
137: }
138:
139: public void setOptional(boolean bOptional) {
140: checkWritable();
141: this .bOptional = bOptional;
142: }
143:
144: public Object defaultValue() {
145: if (type.equals(AttributeType.BOOLEAN)) {
146: return Boolean.FALSE;
147: }
148: return null;
149: }
150:
151: public boolean needsChange(Object value) {
152: if (value == null)
153: return false;
154:
155: if (type.equals(AttributeType.STRING)) {
156: return !(value instanceof String);
157: }
158: if (type.equals(AttributeType.INT)) {
159: return !(value instanceof Long);
160: }
161: if (type.equals(AttributeType.DATE)) {
162: return !(value instanceof Date);
163: }
164: if (type.equals(AttributeType.BOOLEAN)) {
165: return !(value instanceof Boolean);
166: }
167: if (type.equals(AttributeType.CATEGORY)) {
168: if (!(value instanceof Category))
169: return true;
170:
171: Category temp = (Category) value;
172:
173: // look if the attribute category is a ancestor of the value category
174: Category rootCategory = (Category) getConstraint(ConstraintIds.KEY_ROOT_CATEGORY);
175: boolean change = (rootCategory == null || !rootCategory
176: .isAncestorOf(temp));
177: return change;
178: }
179: return false;
180: }
181:
182: public Object convertValue(Object value) {
183: if (type.equals(AttributeType.STRING)) {
184: if (value == null)
185: return null;
186: return value.toString();
187: }
188: if (type.equals(AttributeType.DATE)) {
189: if (value == null)
190: return null;
191: return new Date();
192: }
193: if (type.equals(AttributeType.INT)) {
194: if (value == null)
195: return null;
196:
197: if (value instanceof Boolean)
198: return ((Boolean) value).booleanValue() ? new Long(1)
199: : new Long(0);
200: String str = value.toString().trim().toLowerCase();
201: try {
202: return new Long(str);
203: } catch (NumberFormatException ex) {
204: return null;
205: }
206: }
207: if (type.equals(AttributeType.BOOLEAN)) {
208: if (value == null)
209: return Boolean.FALSE;
210: String str = value.toString().trim().toLowerCase();
211: if (str.equals("0") || str.equals("false"))
212: return Boolean.FALSE;
213: else
214: return Boolean.TRUE;
215: }
216: if (type.equals(AttributeType.CATEGORY)) {
217: if (value == null)
218: return null;
219: if (value instanceof Category) {
220: Category temp = (Category) value;
221: Category rootCategory = (Category) getConstraint(ConstraintIds.KEY_ROOT_CATEGORY);
222: if (temp != null && rootCategory != null
223: && rootCategory.isAncestorOf(temp)) {
224: return value;
225: }
226: }
227: }
228: return null;
229: }
230:
231: public String getAnnotation(String key) {
232: return (String) annotations.get(key);
233: }
234:
235: public String getAnnotation(String key, String defaultValue) {
236: String annotation = getAnnotation(key);
237: return annotation != null ? annotation : defaultValue;
238: }
239:
240: public void setAnnotation(String key, String annotation)
241: throws IllegalAnnotationException {
242: checkWritable();
243: if (annotation == null) {
244: annotations.remove(key);
245: return;
246: }
247: annotations.put(key, annotation);
248: }
249:
250: public String[] getAnnotationKeys() {
251: return (String[]) annotations.keySet().toArray(
252: Tools.EMPTY_STRING_ARRAY);
253: }
254:
255: static private void copy(AttributeImpl source, AttributeImpl dest) {
256: dest.name = (MultiLanguageName) source.name.clone();
257: dest.annotations = (HashMap) source.annotations.clone();
258: dest.type = source.getType();
259: dest.setKey(source.getKey());
260: dest.setOptional(source.isOptional());
261: String[] constraintKeys = source.getConstraintKeys();
262: for (int i = 0; i < constraintKeys.length; i++) {
263: String key = constraintKeys[i];
264: dest.setConstraint(key, source.getConstraint(key));
265: }
266: }
267:
268: public void copy(Object obj) {
269: super .copy((AttributeImpl) obj);
270: copy((AttributeImpl) obj, this );
271: }
272:
273: public Object deepClone() {
274: AttributeImpl clone = new AttributeImpl();
275: super .deepClone(clone);
276: copy(this , clone);
277: return clone;
278: }
279:
280: public Object clone() {
281: AttributeImpl clone = new AttributeImpl();
282: super .clone(clone);
283: copy(this , clone);
284: return clone;
285: }
286:
287: public String toString() {
288: MultiLanguageName name = getName();
289: if (name != null) {
290: return name.toString() + " ID='" + getId() + "'";
291: } else {
292: return getKey() + " " + getId();
293: }
294: }
295:
296: /** @param idResolver if this is set the category will be resolved over the id value*/
297: static public Object parseAttributeValue(Attribute attribute,
298: String text, EntityResolver idResolver)
299: throws ParseException {
300: AttributeType type = attribute.getType();
301: if (type.equals(AttributeType.BOOLEAN)) {
302: return text.trim().equals("true") ? Boolean.TRUE
303: : Boolean.FALSE;
304: }
305:
306: if (type.equals(AttributeType.DATE)) {
307: return new SerializableDateTimeFormat().parseDate(text
308: .trim(), false);
309: }
310:
311: if (type.equals(AttributeType.INT)) {
312: try {
313: return new Long(text.trim());
314: } catch (NumberFormatException ex) {
315: throw new ParseException(ex.getMessage(), 0);
316: }
317: }
318: if (type.equals(AttributeType.STRING)) {
319: return text.trim();
320: }
321: if (type.equals(AttributeType.CATEGORY)) {
322: String path = text.trim();
323: if (path.length() == 0) {
324: return null;
325: }
326: if (idResolver != null) {
327: try {
328: Object id = LocalCache.getId(Category.TYPE, path);
329: return (Category) idResolver.resolve(id);
330: } catch (EntityNotFoundException ex) {
331: throw new ParseException(ex.getMessage(), 0);
332: }
333: } else {
334: CategoryImpl rootCategory = (CategoryImpl) attribute
335: .getConstraint(ConstraintIds.KEY_ROOT_CATEGORY);
336: if (rootCategory == null) {
337: //System.out.println( attribute.getConstraintKeys());
338: throw new ParseException("Can't find "
339: + ConstraintIds.KEY_ROOT_CATEGORY
340: + " for attribute " + attribute, 0);
341: }
342: try {
343: return rootCategory.getCategoryFromPath(path);
344: } catch (Exception ex) {
345: throw new ParseException(ex.getMessage(), 0);
346: }
347: }
348: }
349: throw new ParseException("Unknown attribute type: " + type, 0);
350: }
351:
352: public static String attributeValueToString(Attribute attribute,
353: Object value, boolean idOnly)
354: throws EntityNotFoundException {
355: AttributeType type = attribute.getType();
356: if (type.equals(AttributeType.CATEGORY)) {
357: CategoryImpl rootCategory = (CategoryImpl) attribute
358: .getConstraint(ConstraintIds.KEY_ROOT_CATEGORY);
359: if (idOnly) {
360: return ((RefEntity) value).getId().toString();
361: } else {
362: return rootCategory
363: .getPathForCategory((Category) value);
364: }
365: } else if (type.equals(AttributeType.DATE)) {
366: return new SerializableDateTimeFormat()
367: .formatDate((Date) value);
368: } else {
369: return value.toString();
370: }
371: }
372:
373: static public class IntStrategy {
374: String[] constraintKeys = new String[] { "min", "max" };
375:
376: public String[] getConstraintKeys() {
377: return constraintKeys;
378: }
379:
380: public boolean needsChange(Object value) {
381: return !(value instanceof Long);
382: }
383:
384: public Object convertValue(Object value) {
385: if (value == null)
386: return null;
387:
388: if (value instanceof Boolean)
389: return ((Boolean) value).booleanValue() ? new Long(1)
390: : new Long(0);
391: String str = value.toString().trim().toLowerCase();
392: try {
393: return new Long(str);
394: } catch (NumberFormatException ex) {
395: return null;
396: }
397: }
398: }
399:
400: }
|