/*
* 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();
}
}