View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors.
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   * 
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.graph.property;
25  
26  import java.math.BigDecimal;
27  import java.net.URI;
28  import java.util.Collections;
29  import java.util.Comparator;
30  import java.util.HashMap;
31  import java.util.Map;
32  import java.util.Set;
33  import java.util.UUID;
34  import org.modeshape.common.util.Base64;
35  import org.modeshape.graph.query.model.TypeSystem;
36  
37  /**
38   * 
39   */
40  public class ValueTypeSystem implements TypeSystem {
41  
42      private final String defaultTypeName;
43      protected final ValueFactories valueFactories;
44      protected final ValueFactory<String> stringValueFactory;
45      private final Map<PropertyType, TypeFactory<?>> typeFactoriesByPropertyType;
46      private final Map<String, TypeFactory<?>> typeFactoriesByName;
47      private final Map<String, PropertyType> propertyTypeByName;
48      private final TypeFactory<String> stringFactory;
49      private final TypeFactory<Boolean> booleanFactory;
50      private final TypeFactory<Long> longFactory;
51      private final TypeFactory<Double> doubleFactory;
52      private final TypeFactory<BigDecimal> decimalFactory;
53      private final TypeFactory<?> dateFactory;
54      private final TypeFactory<?> pathFactory;
55      private final TypeFactory<?> referenceFactory;
56      private final TypeFactory<?> binaryFactory;
57  
58      /**
59       * Create a type system using the supplied value factories.
60       * 
61       * @param valueFactories the value factories;
62       * @throws IllegalArgumentException if the value factories are null
63       */
64      public ValueTypeSystem( ValueFactories valueFactories ) {
65          this.valueFactories = valueFactories;
66          this.defaultTypeName = PropertyType.STRING.getName().toUpperCase();
67          Map<PropertyType, TypeFactory<?>> factories = new HashMap<PropertyType, TypeFactory<?>>();
68          this.stringValueFactory = valueFactories.getStringFactory();
69          this.stringFactory = new Factory<String>(stringValueFactory) {
70              /**
71               * {@inheritDoc}
72               * 
73               * @see org.modeshape.graph.property.ValueTypeSystem.Factory#asString(java.lang.Object)
74               */
75              @Override
76              public String asString( Object value ) {
77                  return stringValueFactory.create(value);
78              }
79  
80              /**
81               * {@inheritDoc}
82               * 
83               * @see org.modeshape.graph.property.ValueTypeSystem.Factory#asReadableString(java.lang.Object)
84               */
85              @Override
86              public String asReadableString( Object value ) {
87                  return stringValueFactory.create(value);
88              }
89          };
90          this.booleanFactory = new Factory<Boolean>(valueFactories.getBooleanFactory());
91          this.longFactory = new Factory<Long>(valueFactories.getLongFactory());
92          this.doubleFactory = new Factory<Double>(valueFactories.getDoubleFactory());
93          this.decimalFactory = new Factory<BigDecimal>(valueFactories.getDecimalFactory());
94          this.dateFactory = new Factory<DateTime>(valueFactories.getDateFactory()) {
95  
96              /**
97               * {@inheritDoc}
98               * 
99               * @see org.modeshape.graph.property.ValueTypeSystem.Factory#create(java.lang.String)
100              */
101             @Override
102             public DateTime create( String value ) throws ValueFormatException {
103                 DateTime result = valueFactory.create(value);
104                 // Convert the timestamp to UTC, since that's how everything should be queried ...
105                 return result.toUtcTimeZone();
106             }
107         };
108         this.pathFactory = new Factory<Path>(valueFactories.getPathFactory());
109         this.referenceFactory = new Factory<Reference>(valueFactories.getReferenceFactory());
110         this.binaryFactory = new Factory<Binary>(valueFactories.getBinaryFactory()) {
111             /**
112              * {@inheritDoc}
113              * 
114              * @see org.modeshape.graph.property.ValueTypeSystem.Factory#asReadableString(java.lang.Object)
115              */
116             @Override
117             public String asReadableString( Object value ) {
118                 Binary binary = this.valueFactory.create(value);
119                 // Just print out the SHA-1 hash in Base64, plus length
120                 return "(Binary,length=" + binary.getSize() + ",SHA1=" + Base64.encodeBytes(binary.getHash()) + ")";
121             }
122 
123             /**
124              * {@inheritDoc}
125              * 
126              * @see org.modeshape.graph.property.ValueTypeSystem.Factory#length(java.lang.Object)
127              */
128             @Override
129             public long length( Object value ) {
130                 Binary binary = this.valueFactory.create(value);
131                 return binary != null ? binary.getSize() : 0;
132             }
133         };
134         factories.put(PropertyType.STRING, this.stringFactory);
135         factories.put(PropertyType.BOOLEAN, this.booleanFactory);
136         factories.put(PropertyType.DATE, this.dateFactory);
137         factories.put(PropertyType.DECIMAL, new Factory<BigDecimal>(valueFactories.getDecimalFactory()));
138         factories.put(PropertyType.DOUBLE, this.doubleFactory);
139         factories.put(PropertyType.LONG, this.longFactory);
140         factories.put(PropertyType.NAME, new Factory<Name>(valueFactories.getNameFactory()));
141         factories.put(PropertyType.OBJECT, new Factory<Object>(valueFactories.getObjectFactory()));
142         factories.put(PropertyType.PATH, this.pathFactory);
143         factories.put(PropertyType.REFERENCE, new Factory<Reference>(valueFactories.getReferenceFactory()));
144         factories.put(PropertyType.URI, new Factory<URI>(valueFactories.getUriFactory()));
145         factories.put(PropertyType.UUID, new Factory<UUID>(valueFactories.getUuidFactory()));
146         factories.put(PropertyType.BINARY, this.binaryFactory);
147         this.typeFactoriesByPropertyType = Collections.unmodifiableMap(factories);
148         Map<String, PropertyType> propertyTypeByName = new HashMap<String, PropertyType>();
149         for (Map.Entry<PropertyType, TypeFactory<?>> entry : this.typeFactoriesByPropertyType.entrySet()) {
150             propertyTypeByName.put(entry.getValue().getTypeName(), entry.getKey());
151         }
152         this.propertyTypeByName = Collections.unmodifiableMap(propertyTypeByName);
153         Map<String, TypeFactory<?>> byName = new HashMap<String, TypeFactory<?>>();
154         for (TypeFactory<?> factory : factories.values()) {
155             byName.put(factory.getTypeName(), factory);
156         }
157         this.typeFactoriesByName = Collections.unmodifiableMap(byName);
158     }
159 
160     /**
161      * {@inheritDoc}
162      * 
163      * @see org.modeshape.graph.query.model.TypeSystem#asString(java.lang.Object)
164      */
165     public String asString( Object value ) {
166         return stringValueFactory.create(value);
167     }
168 
169     /**
170      * {@inheritDoc}
171      * 
172      * @see org.modeshape.graph.query.model.TypeSystem#getBooleanFactory()
173      */
174     public TypeFactory<Boolean> getBooleanFactory() {
175         return booleanFactory;
176     }
177 
178     /**
179      * {@inheritDoc}
180      * 
181      * @see org.modeshape.graph.query.model.TypeSystem#getStringFactory()
182      */
183     public TypeFactory<String> getStringFactory() {
184         return this.stringFactory;
185     }
186 
187     /**
188      * {@inheritDoc}
189      * 
190      * @see org.modeshape.graph.query.model.TypeSystem#getDateTimeFactory()
191      */
192     public TypeFactory<?> getDateTimeFactory() {
193         return dateFactory;
194     }
195 
196     /**
197      * {@inheritDoc}
198      * 
199      * @see org.modeshape.graph.query.model.TypeSystem#getDefaultType()
200      */
201     public String getDefaultType() {
202         return defaultTypeName;
203     }
204 
205     /**
206      * {@inheritDoc}
207      * 
208      * @see org.modeshape.graph.query.model.TypeSystem#getDefaultComparator()
209      */
210     @SuppressWarnings( "unchecked" )
211     public Comparator<Object> getDefaultComparator() {
212         return (Comparator<Object>)PropertyType.OBJECT.getComparator();
213     }
214 
215     /**
216      * {@inheritDoc}
217      * 
218      * @see org.modeshape.graph.query.model.TypeSystem#getDoubleFactory()
219      */
220     public TypeFactory<Double> getDoubleFactory() {
221         return doubleFactory;
222     }
223 
224     /**
225      * {@inheritDoc}
226      * 
227      * @see org.modeshape.graph.query.model.TypeSystem#getDecimalFactory()
228      */
229     public TypeFactory<BigDecimal> getDecimalFactory() {
230         return decimalFactory;
231     }
232 
233     /**
234      * {@inheritDoc}
235      * 
236      * @see org.modeshape.graph.query.model.TypeSystem#getLongFactory()
237      */
238     public TypeFactory<Long> getLongFactory() {
239         return longFactory;
240     }
241 
242     /**
243      * {@inheritDoc}
244      * 
245      * @see org.modeshape.graph.query.model.TypeSystem#getPathFactory()
246      */
247     public TypeFactory<?> getPathFactory() {
248         return pathFactory;
249     }
250 
251     /**
252      * {@inheritDoc}
253      * 
254      * @see org.modeshape.graph.query.model.TypeSystem#getReferenceFactory()
255      */
256     public TypeFactory<?> getReferenceFactory() {
257         return referenceFactory;
258     }
259 
260     /**
261      * {@inheritDoc}
262      * 
263      * @see org.modeshape.graph.query.model.TypeSystem#getBinaryFactory()
264      */
265     public TypeFactory<?> getBinaryFactory() {
266         return binaryFactory;
267     }
268 
269     /**
270      * {@inheritDoc}
271      * 
272      * @see org.modeshape.graph.query.model.TypeSystem#getTypeFactory(java.lang.String)
273      */
274     public TypeFactory<?> getTypeFactory( String typeName ) {
275         if (typeName == null) return null;
276         return typeFactoriesByName.get(typeName.toUpperCase()); // may be null
277     }
278 
279     /**
280      * {@inheritDoc}
281      * 
282      * @see org.modeshape.graph.query.model.TypeSystem#getTypeFactory(java.lang.Object)
283      */
284     public TypeFactory<?> getTypeFactory( Object prototype ) {
285         ValueFactory<?> valueFactory = valueFactories.getValueFactory(prototype);
286         if (valueFactory == null) return null;
287         PropertyType type = valueFactory.getPropertyType();
288         assert type != null;
289         return typeFactoriesByPropertyType.get(type);
290     }
291 
292     /**
293      * {@inheritDoc}
294      * 
295      * @see org.modeshape.graph.query.model.TypeSystem#getTypeNames()
296      */
297     public Set<String> getTypeNames() {
298         return typeFactoriesByName.keySet();
299     }
300 
301     /**
302      * {@inheritDoc}
303      * 
304      * @see org.modeshape.graph.query.model.TypeSystem#getCompatibleType(java.lang.String, java.lang.String)
305      */
306     public String getCompatibleType( String type1,
307                                      String type2 ) {
308         if (type1 == null) {
309             return type2 != null ? type2 : getDefaultType();
310         }
311         if (type2 == null) return type1;
312         if (type1.equals(type2)) return type1;
313 
314         // neither is null ...
315         PropertyType ptype1 = propertyTypeByName.get(type1);
316         PropertyType ptype2 = propertyTypeByName.get(type2);
317         assert ptype1 != null;
318         assert ptype2 != null;
319         if (ptype1 == PropertyType.STRING) return type1;
320         if (ptype2 == PropertyType.STRING) return type2;
321         // Dates are compatible with longs ...
322         if (ptype1 == PropertyType.LONG && ptype2 == PropertyType.DATE) return type1;
323         if (ptype1 == PropertyType.DATE && ptype2 == PropertyType.LONG) return type2;
324         // Booleans and longs are compatible ...
325         if (ptype1 == PropertyType.LONG && ptype2 == PropertyType.BOOLEAN) return type1;
326         if (ptype1 == PropertyType.BOOLEAN && ptype2 == PropertyType.LONG) return type2;
327         // Doubles and longs ...
328         if (ptype1 == PropertyType.DOUBLE && ptype2 == PropertyType.LONG) return type1;
329         if (ptype1 == PropertyType.LONG && ptype2 == PropertyType.DOUBLE) return type2;
330         // Paths and names ...
331         if (ptype1 == PropertyType.PATH && ptype2 == PropertyType.NAME) return type1;
332         if (ptype1 == PropertyType.NAME && ptype2 == PropertyType.PATH) return type2;
333 
334         // Otherwise, it's just the default type (string) ...
335         return getDefaultType();
336     }
337 
338     protected class Factory<T> implements TypeFactory<T> {
339         protected final PropertyType type;
340         protected final ValueFactory<T> valueFactory;
341         protected final String typeName;
342 
343         protected Factory( ValueFactory<T> valueFactory ) {
344             this.valueFactory = valueFactory;
345             this.type = this.valueFactory.getPropertyType();
346             this.typeName = type.getName().toUpperCase();
347         }
348 
349         /**
350          * {@inheritDoc}
351          * 
352          * @see org.modeshape.graph.query.model.TypeSystem.TypeFactory#asReadableString(java.lang.Object)
353          */
354         public String asReadableString( Object value ) {
355             return asString(value);
356         }
357 
358         /**
359          * {@inheritDoc}
360          * 
361          * @see org.modeshape.graph.query.model.TypeSystem.TypeFactory#asString(java.lang.Object)
362          */
363         public String asString( Object value ) {
364             if (value instanceof String) {
365                 // Convert to the typed value, then back to a string ...
366                 value = valueFactory.create((String)value);
367             }
368             return stringValueFactory.create(value);
369         }
370 
371         /**
372          * {@inheritDoc}
373          * 
374          * @see org.modeshape.graph.query.model.TypeSystem.TypeFactory#create(java.lang.String)
375          */
376         public T create( String value ) throws ValueFormatException {
377             return valueFactory.create(value);
378         }
379 
380         /**
381          * {@inheritDoc}
382          * 
383          * @see org.modeshape.graph.query.model.TypeSystem.TypeFactory#create(java.lang.Object)
384          */
385         public T create( Object value ) throws ValueFormatException {
386             return valueFactory.create(value);
387         }
388 
389         /**
390          * {@inheritDoc}
391          * 
392          * @see org.modeshape.graph.query.model.TypeSystem.TypeFactory#getType()
393          */
394         @SuppressWarnings( "unchecked" )
395         public Class<T> getType() {
396             return (Class<T>)type.getValueClass();
397         }
398 
399         /**
400          * {@inheritDoc}
401          * 
402          * @see org.modeshape.graph.query.model.TypeSystem.TypeFactory#length(java.lang.Object)
403          */
404         public long length( Object value ) {
405             String str = asString(valueFactory.create(value));
406             return str != null ? str.length() : 0;
407         }
408 
409         /**
410          * {@inheritDoc}
411          * 
412          * @see org.modeshape.graph.query.model.TypeSystem.TypeFactory#getComparator()
413          */
414         @SuppressWarnings( "unchecked" )
415         public Comparator<T> getComparator() {
416             return (Comparator<T>)type.getComparator();
417         }
418 
419         /**
420          * {@inheritDoc}
421          * 
422          * @see org.modeshape.graph.query.model.TypeSystem.TypeFactory#getTypeName()
423          */
424         public String getTypeName() {
425             return typeName;
426         }
427 
428     }
429 }