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.jdbc;
25  
26  import java.sql.ResultSetMetaData;
27  import java.sql.SQLException;
28  import java.sql.Timestamp;
29  import java.sql.Types;
30  import java.util.Collections;
31  import java.util.HashMap;
32  import java.util.Map;
33  import java.util.UUID;
34  
35  import javax.jcr.PropertyType;
36  import javax.jcr.RepositoryException;
37  import javax.jcr.Value;
38  import javax.jcr.ValueFormatException;
39  
40  import org.modeshape.jdbc.types.BlobTransform;
41  import org.modeshape.jdbc.types.BooleanTransform;
42  import org.modeshape.jdbc.types.DateTransform;
43  import org.modeshape.jdbc.types.FloatTransform;
44  import org.modeshape.jdbc.types.LongTransform;
45  import org.modeshape.jdbc.types.StringTransform;
46  import org.modeshape.jdbc.types.UUIDTransform;
47  
48  /**
49   * Provides functionality to convert from JCR {@link PropertyType}s and JDBC types.
50   */
51  public final class JcrType {
52  
53      private static final Map<String, JcrType> TYPE_INFO;
54      
55  	public static final class DefaultDataTypes {
56  		public static final String STRING = PropertyType.TYPENAME_STRING; //$NON-NLS-1$
57  		public static final String BOOLEAN = PropertyType.TYPENAME_BOOLEAN; //$NON-NLS-1$
58  		public static final String LONG = PropertyType.TYPENAME_LONG; //$NON-NLS-1$
59  		public static final String DOUBLE = PropertyType.TYPENAME_DOUBLE; //$NON-NLS-1$
60  		public static final String DECIMAL = PropertyType.TYPENAME_DECIMAL; //$NON-NLS-1$
61  		public static final String DATE = PropertyType.TYPENAME_DATE; //$NON-NLS-1$
62  		public static final String URI = PropertyType.TYPENAME_URI; //$NON-NLS-1$
63  		public static final String WEAK_REF = PropertyType.TYPENAME_WEAKREFERENCE; //$NON-NLS-1$
64  		public static final String UNDEFINED = PropertyType.TYPENAME_UNDEFINED; //$NON-NLS-1$
65  		public static final String BINARY = PropertyType.TYPENAME_BINARY; //$NON-NLS-1$
66  		public static final String REFERENCE = PropertyType.TYPENAME_REFERENCE; //$NON-NLS-1$
67  		public static final String PATH = PropertyType.TYPENAME_PATH; //$NON-NLS-1$
68  		public static final String NAME = PropertyType.TYPENAME_NAME; //$NON-NLS-1$
69  	}
70  
71      static {
72          Map<String, JcrType> types = new HashMap<String, JcrType>();
73          register(types, PropertyType.BINARY, Types.BLOB, JcrBlob.class, 30, Integer.MAX_VALUE, new BlobTransform()); // assumed
74          register(types, PropertyType.BOOLEAN, Types.BOOLEAN, Boolean.class, 5, 1, new BooleanTransform()); // 'true' or 'false'
75          register(types, PropertyType.DATE, Types.TIMESTAMP, Timestamp.class, 30, 10,  new DateTransform()); // yyyy-MM-dd'T'HH:mm:ss.SSS+HH:mm
76          register(types, PropertyType.DOUBLE, Types.FLOAT, Float.class, 20, 20, new FloatTransform()); // assumed
77          register(types, PropertyType.LONG, Types.BIGINT, Long.class, 20, 19, new LongTransform()); // assumed
78          register(types, PropertyType.NAME, Types.VARCHAR, String.class, 20, Integer.MAX_VALUE,new StringTransform()); // assumed
79          register(types, PropertyType.PATH, Types.VARCHAR, String.class, 50, Integer.MAX_VALUE,new StringTransform()); // assumed
80          register(types, PropertyType.REFERENCE, Types.BLOB, UUID.class, UUID.randomUUID().toString().length(), UUID.randomUUID().toString().length(),  new UUIDTransform());
81          register(types, PropertyType.STRING, Types.VARCHAR, String.class, 50, Integer.MAX_VALUE, new StringTransform()); // assumed
82          register(types, PropertyType.UNDEFINED, Types.VARCHAR, String.class, 50, Integer.MAX_VALUE, new StringTransform()); // same as string
83          TYPE_INFO = Collections.unmodifiableMap(types);
84      }
85  
86      private static void register( Map<String, JcrType> types,
87                                    int jcrType,
88                                    int jdbcType,
89                                    Class<?> clazz,
90                                    int displaySize,
91                                    int precision,
92                                    Transform transform) {
93          JcrType type = new JcrType(jcrType, jdbcType, clazz, displaySize, precision, transform);
94          types.put(type.getJcrName(), type);
95      }
96  
97      private final int jcrType;
98      private final String jcrName;
99      private final Class<?> clazz;
100     private final int jdbcType;
101     private final int displaySize;
102     private final int precision;
103     private final Transform transform;
104 
105     protected JcrType( int jcrType,
106                        int jdbcType,
107                        Class<?> clazz,
108                        int displaySize,
109                        int precision,
110                        Transform transform) {
111         this.jcrType = jcrType;
112         this.jcrName = PropertyType.nameFromValue(jcrType);
113         this.clazz = clazz;
114         this.displaySize = displaySize;
115         this.jdbcType = jdbcType;
116         this.precision = precision;
117         this.transform = transform;
118         assert this.jcrName != null;
119         assert this.clazz != null;
120         assert this.displaySize > 0;
121         assert this.transform != null;
122     }
123 
124     /**
125      * Get the name of the JCR type.
126      * 
127      * @return the JCR type name; never null
128      */
129     public String getJcrName() {
130         return jcrName;
131     }
132 
133     /**
134      * Get the JCR {@link PropertyType} value.
135      * 
136      * @return the JCR property type; never null
137      */
138     public int getJcrType() {
139         return jcrType;
140     }
141 
142     /**
143      * Get the JDBC {@link Types} value.
144      * 
145      * @return the JDBC type; never null
146      */
147     public int getJdbcType() {
148         return jdbcType;
149     }
150     
151     /**
152      * Get the default precision used for this JcrType
153      * @return the Integer form of the precision
154      */
155     public Integer getDefaultPrecision() {
156     	return new Integer(precision);
157     }
158     
159     /**
160      * Return the {@link Transform} object to use to transform
161      * the {@link Value} to the correct data type.
162      * @return Transform
163      */
164     protected Transform getTransform() {
165     	return this.transform;
166     }
167     
168     /**
169      * Get the indicator if the value is case sensitive
170      * @return boolean indicating if the value is case sensitive
171      */
172     public boolean isCaseSensitive( ) {
173          switch (getJcrType()) {
174             case PropertyType.DOUBLE:
175             case PropertyType.LONG:
176             case PropertyType.REFERENCE: // conversion is case-insensitive
177             case PropertyType.BOOLEAN: // conversion is case-insensitive
178                 return false;
179         }
180         return true;
181     }
182 
183     
184     /**
185      * Get the indicator if the value is considered a signed value.
186      * 
187      * @return boolean indicating if value is signed.
188      */
189     public boolean isSigned() {
190 	        switch (getJcrType()) {
191 	        case PropertyType.DOUBLE:
192 	        case PropertyType.LONG:
193 	        case PropertyType.DATE:
194 	            return true;
195 	    }
196 	    return false;
197     }
198 
199     /**
200      * Get the Java class used to represent values for this type.
201      * 
202      * @return the representation class; never null
203      */
204     public Class<?> getRepresentationClass() {
205         return clazz;
206     }
207 
208     /**
209      * Get the nominal display size for the given type. This may not be large enough for certain string and binary values.
210      * 
211      * @return the nominal display size; always positive
212      * @see ResultSetMetaData#getColumnDisplaySize(int)
213      */
214     public int getNominalDisplaySize() {
215         return displaySize;
216     }
217     
218     public Object translateValue(Value value ) throws SQLException {
219         if (value == null) return null;      
220          try {
221         	 return this.getTransform().transform(value);
222 
223         } catch (ValueFormatException ve) {
224             throw new SQLException(ve.getLocalizedMessage(), ve);
225         } catch (IllegalStateException ie) {
226             throw new SQLException(ie.getLocalizedMessage(), ie);
227         } catch (RepositoryException e) {
228             throw new SQLException(e.getLocalizedMessage(), e);
229         }
230 
231     }
232     
233     public static Object translateValueToJDBC(Value value) throws SQLException {
234     	String jcrName = PropertyType.nameFromValue(value.getType());
235     	JcrType jcrtype = typeInfo(jcrName);
236     	return jcrtype.translateValue(value);
237     }
238 
239     /**
240      * Get the immutable built-in map from the type names to the Java representation class.
241      * 
242      * @return the built-in type map
243      */
244     public static Map<String, JcrType> builtInTypeMap() {
245         return TYPE_INFO;
246     }
247     
248     public static JcrType typeInfo( String typeName ) {
249     	return TYPE_INFO.get(typeName);
250     }
251     
252     public static JcrType typeInfo(int jcrType) {
253     	return typeInfo(PropertyType.nameFromValue(jcrType) );
254      }
255     
256 }