/* * ModeShape (http://www.modeshape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.modeshape.jdbc; import java.math.BigDecimal; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Timestamp; import java.sql.Types; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.UUID; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.Value; import javax.jcr.ValueFormatException; import org.modeshape.jdbc.types.BlobTransform; import org.modeshape.jdbc.types.BooleanTransform; import org.modeshape.jdbc.types.DateTransform; import org.modeshape.jdbc.types.DecimalTransform; import org.modeshape.jdbc.types.DoubleTransform; import org.modeshape.jdbc.types.LongTransform; import org.modeshape.jdbc.types.StringTransform; import org.modeshape.jdbc.types.UUIDTransform; /** * Provides functionality to convert from JCR {@link PropertyType}s and JDBC types. */ public final class JcrType { private static final int UUID_LENGTH = UUID.randomUUID().toString().length(); private static final Map<String, JcrType> TYPE_INFO; public static final class DefaultDataTypes { public static final String STRING = PropertyType.TYPENAME_STRING; public static final String BOOLEAN = PropertyType.TYPENAME_BOOLEAN; public static final String LONG = PropertyType.TYPENAME_LONG; public static final String DOUBLE = PropertyType.TYPENAME_DOUBLE; public static final String DECIMAL = PropertyType.TYPENAME_DECIMAL; public static final String DATE = PropertyType.TYPENAME_DATE; public static final String URI = PropertyType.TYPENAME_URI; public static final String WEAK_REF = PropertyType.TYPENAME_WEAKREFERENCE; public static final String UNDEFINED = PropertyType.TYPENAME_UNDEFINED; public static final String BINARY = PropertyType.TYPENAME_BINARY; public static final String REFERENCE = PropertyType.TYPENAME_REFERENCE; public static final String PATH = PropertyType.TYPENAME_STRING; public static final String NAME = PropertyType.TYPENAME_STRING; } static { Map<String, JcrType> types = new HashMap<String, JcrType>(); register(types, PropertyType.BINARY, Types.BLOB, "BLOB", JcrBlob.class, 30, Integer.MAX_VALUE, new BlobTransform()); // assumed register(types, PropertyType.BOOLEAN, Types.BOOLEAN, "BOOLEAN", Boolean.class, 5, 1, new BooleanTransform()); // 'true' or // 'false' register(types, PropertyType.DATE, Types.TIMESTAMP, "TIMESTAMP", Timestamp.class, 30, 10, new DateTransform()); // yyyy-MM-dd'T'HH:mm:ss.SSS+HH:mm register(types, PropertyType.DOUBLE, Types.DOUBLE, "DOUBLE", Double.class, 20, 20, new DoubleTransform()); // assumed register(types, PropertyType.DECIMAL, Types.DECIMAL, "BIGDECIMAL", BigDecimal.class, 20, 20, new DecimalTransform()); // assumed register(types, PropertyType.LONG, Types.BIGINT, "LONG", Long.class, 20, 19, new LongTransform()); // assumed register(types, PropertyType.NAME, Types.VARCHAR, "STRING", String.class, 20, Integer.MAX_VALUE, new StringTransform()); // assumed register(types, PropertyType.PATH, Types.VARCHAR, "STRING", String.class, 50, Integer.MAX_VALUE, new StringTransform()); // assumed register(types, PropertyType.REFERENCE, Types.VARCHAR, "STRING", UUID.class, UUID_LENGTH, UUID_LENGTH, new UUIDTransform()); register(types, PropertyType.WEAKREFERENCE, Types.VARCHAR, "STRING", UUID.class, UUID_LENGTH, UUID_LENGTH, new UUIDTransform()); register(types, PropertyType.URI, Types.VARCHAR, "STRING", String.class, 50, Integer.MAX_VALUE, new StringTransform()); // assumed register(types, PropertyType.STRING, Types.VARCHAR, "STRING", String.class, 50, Integer.MAX_VALUE, new StringTransform()); // assumed register(types, PropertyType.UNDEFINED, Types.VARCHAR, "STRING", String.class, 50, Integer.MAX_VALUE, new StringTransform()); // same // as // string TYPE_INFO = Collections.unmodifiableMap(types); } private static void register( Map<String, JcrType> types, int jcrType, int jdbcType, String typeName, Class<?> clazz, int displaySize, int precision, Transform transform ) { JcrType type = new JcrType(jcrType, jdbcType, typeName, clazz, displaySize, precision, transform); types.put(type.getJcrName(), type); } private final int jcrType; private final String jcrName; private final Class<?> clazz; private final int jdbcType; private final String typeName; private final int displaySize; private final int precision; private final Transform transform; protected JcrType( int jcrType, int jdbcType, String typeName, Class<?> clazz, int displaySize, int precision, Transform transform ) { this.jcrType = jcrType; this.jcrName = PropertyType.nameFromValue(jcrType).toUpperCase(); this.clazz = clazz; this.displaySize = displaySize; this.jdbcType = jdbcType; this.typeName = typeName; this.precision = precision; this.transform = transform; assert this.jcrName != null; assert this.clazz != null; assert this.displaySize > 0; assert this.transform != null; } /** * Get the name of the JCR type. * * @return the JCR type name; never null */ public String getJcrName() { return jcrName; } /** * Get the JCR {@link PropertyType} value. * * @return the JCR property type; never null */ public int getJcrType() { return jcrType; } /** * Get the JDBC {@link Types} value. * * @return the JDBC type; never null */ public int getJdbcType() { return jdbcType; } /** * Get the native type name associated with the JDBC {@link Types} value. * * @return the native JDBC type name; never null */ public String getJdbcTypeName() { return this.typeName; } /** * Get the default precision used for this JcrType * * @return the Integer form of the precision */ public Integer getDefaultPrecision() { return new Integer(precision); } /** * Return the {@link Transform} object to use to transform the {@link Value} to the correct data type. * * @return Transform */ protected Transform getTransform() { return this.transform; } /** * Get the indicator if the value is case sensitive * * @return boolean indicating if the value is case sensitive */ public boolean isCaseSensitive() { switch (getJcrType()) { case PropertyType.DOUBLE: case PropertyType.LONG: case PropertyType.DECIMAL: case PropertyType.WEAKREFERENCE: case PropertyType.REFERENCE: // conversion is case-insensitive case PropertyType.BOOLEAN: // conversion is case-insensitive return false; } return true; } /** * Get the indicator if the value is considered a signed value. * * @return boolean indicating if value is signed. */ public boolean isSigned() { switch (getJcrType()) { case PropertyType.DOUBLE: case PropertyType.LONG: case PropertyType.DECIMAL: case PropertyType.DATE: return true; } return false; } /** * Get the Java class used to represent values for this type. * * @return the representation class; never null */ public Class<?> getRepresentationClass() { return clazz; } /** * Get the nominal display size for the given type. This may not be large enough for certain string and binary values. * * @return the nominal display size; always positive * @see ResultSetMetaData#getColumnDisplaySize(int) */ public int getNominalDisplaySize() { return displaySize; } public Object translateValue( Value value ) throws SQLException { if (value == null) return null; try { return this.getTransform().transform(value); } catch (ValueFormatException ve) { throw new SQLException(ve.getLocalizedMessage(), ve); } catch (IllegalStateException ie) { throw new SQLException(ie.getLocalizedMessage(), ie); } catch (RepositoryException e) { throw new SQLException(e.getLocalizedMessage(), e); } } public static Object translateValueToJDBC( Value value ) throws SQLException { String jcrName = PropertyType.nameFromValue(value.getType()); JcrType jcrtype = typeInfo(jcrName); return jcrtype.translateValue(value); } public static JcrType typeInfo( String jcrTypeName ) { return TYPE_INFO.get(jcrTypeName.toUpperCase()); } public static JcrType typeInfo( int jcrType ) { return typeInfo(PropertyType.nameFromValue(jcrType)); } public static String jdbcType( String jcrTypeName ) { JcrType t = typeInfo(jcrTypeName); return t.getJdbcTypeName(); } }