KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > repo > domain > PropertyValue


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.repo.domain;
18
19 import java.io.Serializable JavaDoc;
20 import java.util.ArrayList JavaDoc;
21 import java.util.Collection JavaDoc;
22 import java.util.Date JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.Map JavaDoc;
25
26 import org.alfresco.error.AlfrescoRuntimeException;
27 import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
28 import org.alfresco.service.cmr.repository.ContentData;
29 import org.alfresco.service.cmr.repository.NodeRef;
30 import org.alfresco.service.cmr.repository.Path;
31 import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
32 import org.alfresco.service.namespace.QName;
33 import org.alfresco.util.EqualsHelper;
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36
37 /**
38  * Immutable property value storage class.
39  * <p>
40  * The
41  *
42  * @author Derek Hulley
43  */

44 public class PropertyValue implements Cloneable JavaDoc, Serializable JavaDoc
45 {
46     private static final long serialVersionUID = -497902497351493075L;
47
48     /** used to take care of empty strings being converted to nulls by the database */
49     private static final String JavaDoc STRING_EMPTY = "";
50     
51     private static Log logger = LogFactory.getLog(PropertyValue.class);
52     private static Log loggerOracle = LogFactory.getLog(PropertyValue.class.getName() + ".oracle");
53
54     /** potential value types */
55     private static enum ValueType
56     {
57         NULL
58         {
59             @Override JavaDoc
60             Serializable JavaDoc convert(Serializable JavaDoc value)
61             {
62                 return null;
63             }
64         },
65         BOOLEAN
66         {
67             @Override JavaDoc
68             Serializable JavaDoc convert(Serializable JavaDoc value)
69             {
70                 return DefaultTypeConverter.INSTANCE.convert(Boolean JavaDoc.class, value);
71             }
72         },
73         INTEGER
74         {
75             @Override JavaDoc
76             protected ValueType getPersistedType(Serializable JavaDoc value)
77             {
78                 return ValueType.LONG;
79             }
80
81             @Override JavaDoc
82             Serializable JavaDoc convert(Serializable JavaDoc value)
83             {
84                 return DefaultTypeConverter.INSTANCE.convert(Integer JavaDoc.class, value);
85             }
86         },
87         LONG
88         {
89             @Override JavaDoc
90             Serializable JavaDoc convert(Serializable JavaDoc value)
91             {
92                 return DefaultTypeConverter.INSTANCE.convert(Long JavaDoc.class, value);
93             }
94         },
95         FLOAT
96         {
97             @Override JavaDoc
98             Serializable JavaDoc convert(Serializable JavaDoc value)
99             {
100                 return DefaultTypeConverter.INSTANCE.convert(Float JavaDoc.class, value);
101             }
102         },
103         DOUBLE
104         {
105             @Override JavaDoc
106             Serializable JavaDoc convert(Serializable JavaDoc value)
107             {
108                 return DefaultTypeConverter.INSTANCE.convert(Double JavaDoc.class, value);
109             }
110         },
111         STRING
112         {
113             /**
114              * Strings longer than the maximum of 1024 characters will be serialized.
115              */

116             @Override JavaDoc
117             protected ValueType getPersistedType(Serializable JavaDoc value)
118             {
119                 if (value instanceof String JavaDoc)
120                 {
121                     String JavaDoc valueStr = (String JavaDoc) value;
122                     if (valueStr.length() > 1024)
123                     {
124                         return ValueType.SERIALIZABLE;
125                     }
126                 }
127                 return ValueType.STRING;
128             }
129
130             @Override JavaDoc
131             Serializable JavaDoc convert(Serializable JavaDoc value)
132             {
133                 return DefaultTypeConverter.INSTANCE.convert(String JavaDoc.class, value);
134             }
135         },
136         DATE
137         {
138             @Override JavaDoc
139             protected ValueType getPersistedType(Serializable JavaDoc value)
140             {
141                 return ValueType.STRING;
142             }
143
144             @Override JavaDoc
145             Serializable JavaDoc convert(Serializable JavaDoc value)
146             {
147                 return DefaultTypeConverter.INSTANCE.convert(Date JavaDoc.class, value);
148             }
149         },
150         SERIALIZABLE
151         {
152             @Override JavaDoc
153             Serializable JavaDoc convert(Serializable JavaDoc value)
154             {
155                 return value;
156             }
157         },
158         CONTENT
159         {
160             @Override JavaDoc
161             protected ValueType getPersistedType(Serializable JavaDoc value)
162             {
163                 return ValueType.STRING;
164             }
165
166             @Override JavaDoc
167             Serializable JavaDoc convert(Serializable JavaDoc value)
168             {
169                 return DefaultTypeConverter.INSTANCE.convert(ContentData.class, value);
170             }
171         },
172         NODEREF
173         {
174             @Override JavaDoc
175             protected ValueType getPersistedType(Serializable JavaDoc value)
176             {
177                 return ValueType.STRING;
178             }
179
180             @Override JavaDoc
181             Serializable JavaDoc convert(Serializable JavaDoc value)
182             {
183                 return DefaultTypeConverter.INSTANCE.convert(NodeRef.class, value);
184             }
185         },
186         QNAME
187         {
188             @Override JavaDoc
189             protected ValueType getPersistedType(Serializable JavaDoc value)
190             {
191                 return ValueType.STRING;
192             }
193
194             @Override JavaDoc
195             Serializable JavaDoc convert(Serializable JavaDoc value)
196             {
197                 return DefaultTypeConverter.INSTANCE.convert(QName.class, value);
198             }
199         },
200         PATH
201         {
202             @Override JavaDoc
203             protected ValueType getPersistedType(Serializable JavaDoc value)
204             {
205                 return ValueType.SERIALIZABLE;
206             }
207
208             @Override JavaDoc
209             Serializable JavaDoc convert(Serializable JavaDoc value)
210             {
211                 return DefaultTypeConverter.INSTANCE.convert(Path.class, value);
212             }
213         };
214         
215         /**
216          * Override if the type gets persisted in a different format.
217          *
218          * @param value the actual value that is to be persisted. May not be null.
219          */

220         protected ValueType getPersistedType(Serializable JavaDoc value)
221         {
222             return this;
223         }
224         
225         /**
226          * @see DefaultTypeConverter.INSTANCE#convert(Class, Object)
227          */

228         abstract Serializable JavaDoc convert(Serializable JavaDoc value);
229         
230         protected ArrayList JavaDoc<Serializable JavaDoc> convert(Collection JavaDoc collection)
231         {
232             ArrayList JavaDoc<Serializable JavaDoc> arrayList = new ArrayList JavaDoc<Serializable JavaDoc>(collection.size());
233             for (Object JavaDoc object : collection)
234             {
235                 Serializable JavaDoc newValue = null;
236                 if (object != null)
237                 {
238                     if (!(object instanceof Serializable JavaDoc))
239                     {
240                         throw new AlfrescoRuntimeException("Collection values must contain Serializable instances: \n" +
241                                 " value type: " + this + "\n" +
242                                 " collection: " + collection + "\n" +
243                                 " value: " + object);
244                     }
245                     Serializable JavaDoc value = (Serializable JavaDoc) object;
246                     newValue = convert(value);
247                 }
248                 arrayList.add(newValue);
249             }
250             // done
251
return arrayList;
252         }
253     }
254     
255     /**
256      * Determine the actual value type to aid in more concise persistence.
257      *
258      * @param value the value that is to be persisted
259      * @return Returns the value type equivalent of the
260      */

261     private static ValueType getActualType(Serializable JavaDoc value)
262     {
263         if (value == null)
264         {
265             return ValueType.NULL;
266         }
267         else if (value instanceof Boolean JavaDoc)
268         {
269             return ValueType.BOOLEAN;
270         }
271         else if ((value instanceof Integer JavaDoc) || (value instanceof Long JavaDoc))
272         {
273             return ValueType.LONG;
274         }
275         else if (value instanceof Float JavaDoc)
276         {
277             return ValueType.FLOAT;
278         }
279         else if (value instanceof Double JavaDoc)
280         {
281             return ValueType.DOUBLE;
282         }
283         else if (value instanceof String JavaDoc)
284         {
285             return ValueType.STRING;
286         }
287         else if (value instanceof Date JavaDoc)
288         {
289             return ValueType.DATE;
290         }
291         else if (value instanceof ContentData)
292         {
293             return ValueType.CONTENT;
294         }
295         else if (value instanceof NodeRef)
296         {
297             return ValueType.NODEREF;
298         }
299         else if (value instanceof QName)
300         {
301             return ValueType.QNAME;
302         }
303         else if (value instanceof Path)
304         {
305             return ValueType.PATH;
306         }
307         else
308         {
309             // type is not recognised as belonging to any particular slot
310
return ValueType.SERIALIZABLE;
311         }
312     }
313     
314     /** a mapping from a property type <code>QName</code> to the corresponding value type */
315     private static Map JavaDoc<QName, ValueType> valueTypesByPropertyType;
316     static
317     {
318         valueTypesByPropertyType = new HashMap JavaDoc<QName, ValueType>(17);
319         valueTypesByPropertyType.put(DataTypeDefinition.ANY, ValueType.SERIALIZABLE);
320         valueTypesByPropertyType.put(DataTypeDefinition.BOOLEAN, ValueType.BOOLEAN);
321         valueTypesByPropertyType.put(DataTypeDefinition.INT, ValueType.INTEGER);
322         valueTypesByPropertyType.put(DataTypeDefinition.LONG, ValueType.LONG);
323         valueTypesByPropertyType.put(DataTypeDefinition.DOUBLE, ValueType.DOUBLE);
324         valueTypesByPropertyType.put(DataTypeDefinition.FLOAT, ValueType.FLOAT);
325         valueTypesByPropertyType.put(DataTypeDefinition.DATE, ValueType.DATE);
326         valueTypesByPropertyType.put(DataTypeDefinition.DATETIME, ValueType.DATE);
327         valueTypesByPropertyType.put(DataTypeDefinition.CATEGORY, ValueType.NODEREF);
328         valueTypesByPropertyType.put(DataTypeDefinition.CONTENT, ValueType.CONTENT);
329         valueTypesByPropertyType.put(DataTypeDefinition.TEXT, ValueType.STRING);
330         valueTypesByPropertyType.put(DataTypeDefinition.NODE_REF, ValueType.NODEREF);
331         valueTypesByPropertyType.put(DataTypeDefinition.PATH, ValueType.PATH);
332         valueTypesByPropertyType.put(DataTypeDefinition.QNAME, ValueType.QNAME);
333     }
334
335     /** the type of the property, prior to serialization persistence */
336     private ValueType actualType;
337     /** true if the property values are contained in a collection */
338     private boolean isMultiValued;
339     /** the type of persistence used */
340     private ValueType persistedType;
341     
342     private Boolean JavaDoc booleanValue;
343     private Long JavaDoc longValue;
344     private Float JavaDoc floatValue;
345     private Double JavaDoc doubleValue;
346     private String JavaDoc stringValue;
347     private Serializable JavaDoc serializableValue;
348     
349     /**
350      * default constructor
351      */

352     public PropertyValue()
353     {
354     }
355     
356     /**
357      * Construct a new property value.
358      *
359      * @param typeQName the dictionary-defined property type to store the property as
360      * @param value the value to store. This will be converted into a format compatible
361      * with the type given
362      *
363      * @throws java.lang.UnsupportedOperationException if the value cannot be converted to the
364      * type given
365      */

366     public PropertyValue(QName typeQName, Serializable JavaDoc value)
367     {
368         this.actualType = PropertyValue.getActualType(value);
369         if (value == null)
370         {
371             setPersistedValue(ValueType.NULL, null);
372             setMultiValued(false);
373         }
374         else if (value instanceof Collection JavaDoc)
375         {
376             Collection JavaDoc collection = (Collection JavaDoc) value;
377             ValueType collectionValueType = makeValueType(typeQName);
378             // convert the collection values - we need to do this to ensure that the
379
// values provided conform to the given type
380
ArrayList JavaDoc<Serializable JavaDoc> convertedCollection = collectionValueType.convert(collection);
381             // the persisted type is, nonetheless, a serializable
382
setPersistedValue(ValueType.SERIALIZABLE, convertedCollection);
383             setMultiValued(true);
384         }
385         else
386         {
387             // get the persisted type
388
ValueType persistedValueType = this.actualType.getPersistedType(value);
389             // convert to the persistent type
390
value = persistedValueType.convert(value);
391             setPersistedValue(persistedValueType, value);
392             setMultiValued(false);
393         }
394     }
395     
396     /**
397      * Helper method to convert the type <code>QName</code> into a <code>ValueType</code>
398      *
399      * @return Returns the <code>ValueType</code> - never null
400      */

401     private ValueType makeValueType(QName typeQName)
402     {
403         ValueType valueType = valueTypesByPropertyType.get(typeQName);
404         if (valueType == null)
405         {
406             throw new AlfrescoRuntimeException(
407                     "Property type not recognised: \n" +
408                     " type: " + typeQName + "\n" +
409                     " property: " + this);
410         }
411         return valueType;
412     }
413     
414     @Override JavaDoc
415     public boolean equals(Object JavaDoc obj)
416     {
417         if (this == obj)
418         {
419             return true;
420         }
421         if (obj == null)
422         {
423             return false;
424         }
425         if (obj instanceof PropertyValue)
426         {
427             PropertyValue that = (PropertyValue) obj;
428             return (this.actualType.equals(that.actualType) &&
429                     EqualsHelper.nullSafeEquals(this.booleanValue, that.booleanValue) &&
430                     EqualsHelper.nullSafeEquals(this.longValue, that.longValue) &&
431                     EqualsHelper.nullSafeEquals(this.floatValue, that.floatValue) &&
432                     EqualsHelper.nullSafeEquals(this.doubleValue, that.doubleValue) &&
433                     EqualsHelper.nullSafeEquals(this.stringValue, that.stringValue) &&
434                     EqualsHelper.nullSafeEquals(this.serializableValue, that.serializableValue)
435                     );
436             
437         }
438         else
439         {
440             return false;
441         }
442     }
443     
444     @Override JavaDoc
445     public int hashCode()
446     {
447         int h = 0;
448         if (actualType != null)
449             h = actualType.hashCode();
450         Serializable JavaDoc persistedValue = getPersistedValue();
451         if (persistedValue != null)
452             h += 17 * persistedValue.hashCode();
453         return h;
454     }
455     
456     @Override JavaDoc
457     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc
458     {
459         return super.clone();
460     }
461
462     @Override JavaDoc
463     public String JavaDoc toString()
464     {
465         StringBuilder JavaDoc sb = new StringBuilder JavaDoc(128);
466         sb.append("PropertyValue")
467           .append("[actual-type=").append(actualType)
468           .append(", multi-valued=").append(isMultiValued)
469           .append(", value-type=").append(persistedType)
470           .append(", value=").append(getPersistedValue())
471           .append("]");
472         return sb.toString();
473     }
474
475     public String JavaDoc getActualType()
476     {
477         return actualType.toString();
478     }
479
480     public void setActualType(String JavaDoc actualType)
481     {
482         this.actualType = ValueType.valueOf(actualType);
483     }
484
485     public boolean isMultiValued()
486     {
487         return isMultiValued;
488     }
489
490     public void setMultiValued(boolean isMultiValued)
491     {
492         this.isMultiValued = isMultiValued;
493     }
494
495     public String JavaDoc getPersistedType()
496     {
497         return persistedType.toString();
498     }
499     public void setPersistedType(String JavaDoc persistedType)
500     {
501         this.persistedType = ValueType.valueOf(persistedType);
502     }
503     
504     /**
505      * Stores the value in the correct slot based on the type of persistence requested.
506      * No conversion is done.
507      *
508      * @param persistedType the value type
509      * @param value the value - it may only be null if the persisted type is {@link ValueType#NULL}
510      */

511     public void setPersistedValue(ValueType persistedType, Serializable JavaDoc value)
512     {
513         switch (persistedType)
514         {
515             case NULL:
516                 if (value != null)
517                 {
518                     throw new AlfrescoRuntimeException("Value must be null for persisted type: " + persistedType);
519                 }
520                 break;
521             case BOOLEAN:
522                 this.booleanValue = (Boolean JavaDoc) value;
523                 break;
524             case LONG:
525                 this.longValue = (Long JavaDoc) value;
526                 break;
527             case FLOAT:
528                 this.floatValue = (Float JavaDoc) value;
529                 break;
530             case DOUBLE:
531                 this.doubleValue = (Double JavaDoc) value;
532                 break;
533             case STRING:
534                 this.stringValue = (String JavaDoc) value;
535                 break;
536             case SERIALIZABLE:
537                 this.serializableValue = (Serializable JavaDoc) value;
538                 break;
539             default:
540                 throw new AlfrescoRuntimeException("Unrecognised value type: " + persistedType);
541         }
542         // we store the type that we persisted as
543
this.persistedType = persistedType;
544     }
545
546     /**
547      * @return Returns the persisted value, keying off the persisted value type
548      */

549     private Serializable JavaDoc getPersistedValue()
550     {
551         switch (persistedType)
552         {
553             case NULL:
554                 return null;
555             case BOOLEAN:
556                 return this.booleanValue;
557             case LONG:
558                 return this.longValue;
559             case FLOAT:
560                 return this.floatValue;
561             case DOUBLE:
562                 return this.doubleValue;
563             case STRING:
564                 // Oracle stores empty strings as 'null'...
565
if (this.stringValue == null)
566                 {
567                     // We know that we stored a non-null string, but now it is null.
568
// It can only mean one thing - Oracle
569
if (loggerOracle.isDebugEnabled())
570                     {
571                         logger.debug("string_value is 'null'. Forcing to empty String");
572                     }
573                     return PropertyValue.STRING_EMPTY;
574                 }
575                 else
576                 {
577                     return this.stringValue;
578                 }
579             case SERIALIZABLE:
580                 return this.serializableValue;
581             default:
582                 throw new AlfrescoRuntimeException("Unrecognised value type: " + persistedType);
583         }
584     }
585
586     /**
587      * Fetches the value as a desired type. Collections (i.e. multi-valued properties)
588      * will be converted as a whole to ensure that all the values returned within the
589      * collection match the given type.
590      *
591      * @param typeQName the type required for the return value
592      * @return Returns the value of this property as the desired type, or a <code>Collection</code>
593      * of values of the required type
594      *
595      * @throws java.lang.UnsupportedOperationException if the value cannot be converted to the
596      * type given
597      *
598      * @see DataTypeDefinition#ANY The static qualified names for the types
599      */

600     public Serializable JavaDoc getValue(QName typeQName)
601     {
602         // first check for null
603

604         ValueType requiredType = makeValueType(typeQName);
605         if (requiredType == ValueType.SERIALIZABLE)
606         {
607             // the required type must be the actual type
608
requiredType = this.actualType;
609         }
610         
611         // we need to convert
612
Serializable JavaDoc ret = null;
613         if (persistedType == ValueType.NULL)
614         {
615             ret = null;
616         }
617         else if (this.isMultiValued)
618         {
619             // collections are always stored
620
Collection JavaDoc collection = (Collection JavaDoc) this.serializableValue;
621             // convert the collection values - we need to do this to ensure that the
622
// values provided conform to the given type
623
ArrayList JavaDoc<Serializable JavaDoc> convertedCollection = requiredType.convert(collection);
624             ret = convertedCollection;
625         }
626         else
627         {
628             Serializable JavaDoc persistedValue = getPersistedValue();
629             // convert the type
630
ret = requiredType.convert(persistedValue);
631         }
632         // done
633
if (logger.isDebugEnabled())
634         {
635             logger.debug("Fetched value: \n" +
636                     " property value: " + this + "\n" +
637                     " requested type: " + requiredType + "\n" +
638                     " result: " + ret);
639         }
640         return ret;
641     }
642     
643     public boolean getBooleanValue()
644     {
645         if (booleanValue == null)
646             return false;
647         else
648             return booleanValue.booleanValue();
649     }
650     public void setBooleanValue(boolean value)
651     {
652         this.booleanValue = Boolean.valueOf(value);
653     }
654     
655     public long getLongValue()
656     {
657         if (longValue == null)
658             return 0;
659         else
660             return longValue.longValue();
661     }
662     public void setLongValue(long value)
663     {
664         this.longValue = Long.valueOf(value);
665     }
666     
667     public float getFloatValue()
668     {
669         if (floatValue == null)
670             return 0.0F;
671         else
672             return floatValue.floatValue();
673     }
674     public void setFloatValue(float value)
675     {
676         this.floatValue = Float.valueOf(value);
677     }
678     
679     public double getDoubleValue()
680     {
681         if (doubleValue == null)
682             return 0.0;
683         else
684             return doubleValue.doubleValue();
685     }
686     public void setDoubleValue(double value)
687     {
688         this.doubleValue = Double.valueOf(value);
689     }
690     
691     public String JavaDoc getStringValue()
692     {
693         return stringValue;
694     }
695     public void setStringValue(String JavaDoc value)
696     {
697         this.stringValue = value;
698     }
699     
700     public Serializable JavaDoc getSerializableValue()
701     {
702         return serializableValue;
703     }
704     public void setSerializableValue(Serializable JavaDoc value)
705     {
706         this.serializableValue = value;
707     }
708 }
709
Popular Tags