001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.jdbc.metadata;
012:
013: import com.versant.core.jdbc.sql.SqlDriver;
014: import com.versant.core.jdbc.JdbcTypeRegistry;
015: import com.versant.core.jdbc.JdbcConverterFactory;
016: import com.versant.core.metadata.MetaDataUtils;
017:
018: import java.sql.Types;
019: import java.util.*;
020:
021: import com.versant.core.common.BindingSupportImpl;
022:
023: /**
024: * This resolves the mapping for a field against mapping information from
025: * the datastore and the SqlDriver.
026: *
027: * @see JdbcJavaTypeMapping
028: * @see JdbcTypeMapping
029: * @see #init
030: * @see #resolveMapping
031: */
032: public final class JdbcMappingResolver implements JdbcTypeRegistry {
033:
034: private String database;
035: private HashMap javaTypeMappings; // Class -> JdbcJavaTypeMapping
036: private JdbcTypeMapping[] typeMappings; // indexed by JDBC type
037:
038: private static final int FIRST_TYPE = Types.BIT;
039: private static final int LAST_TYPE = Types.REF;
040:
041: public JdbcMappingResolver() {
042: }
043:
044: /**
045: * Merge mappings from the sqlDriver and the datastore into a
046: * combined array of type mappings. This is used to map JDBC
047: * type codes from java.sql.Types to column properties.
048: */
049: public void init(SqlDriver sqlDriver, List dsTypeMappings,
050: List dsJavaTypeMappings) {
051: database = sqlDriver.getName();
052:
053: JdbcTypeMapping[] sqlDriverTypeMappings = sqlDriver
054: .getTypeMappings();
055: int n = sqlDriverTypeMappings.length;
056: int q = dsTypeMappings.size();
057: typeMappings = new JdbcTypeMapping[LAST_TYPE - FIRST_TYPE];
058: for (int i = 0; i < n; i++) {
059: JdbcTypeMapping m = null;
060: JdbcTypeMapping dm = sqlDriverTypeMappings[i];
061: int jdbcType = dm.getJdbcType();
062: for (int j = 0; j < q; j++) {
063: JdbcTypeMapping dsm = (JdbcTypeMapping) dsTypeMappings
064: .get(j);
065: if (dsm.match(jdbcType, database)) {
066: dsm.copyFrom(dm);
067: m = dsm;
068: break;
069: }
070: }
071: if (m == null)
072: m = (JdbcTypeMapping) dm.clone();
073: typeMappings[m.getJdbcType() - FIRST_TYPE] = m;
074: }
075:
076: javaTypeMappings = sqlDriver.getJavaTypeMappings();
077: n = dsJavaTypeMappings.size();
078: for (int i = 0; i < n; i++) {
079: JdbcJavaTypeMapping m = (JdbcJavaTypeMapping) dsJavaTypeMappings
080: .get(i);
081: String mdb = m.getDatabase();
082: if (mdb != null && !mdb.equals(database))
083: continue;
084: JdbcJavaTypeMapping sm = (JdbcJavaTypeMapping) javaTypeMappings
085: .get(m.getJavaType());
086: if (sm != null)
087: m.copyFrom(sm);
088: javaTypeMappings.put(m.getJavaType(), m);
089: }
090: }
091:
092: public String getDatabase() {
093: return database;
094: }
095:
096: public JdbcTypeMapping[] getTypeMappings() {
097: return typeMappings;
098: }
099:
100: public HashMap getJavaTypeMappings() {
101: return javaTypeMappings;
102: }
103:
104: /**
105: * Resolve the mapping for javaType. The returned mapping will be complete
106: * and can be used to create a JdbcColumn.
107: */
108: public JdbcJavaTypeMapping resolveMapping(Class javaType) {
109: return resolveMapping(null, null, javaType);
110: }
111:
112: /**
113: * Resolve the mapping for fieldName using the fieldMapping provided
114: * and our mapping tables. The returned mapping will be complete and
115: * can be used to create a JdbcColumn.
116: */
117: public JdbcJavaTypeMapping resolveMapping(
118: JdbcJavaTypeMapping fieldMapping, String fieldName,
119: Class javaType) {
120: JdbcJavaTypeMapping ans = fieldMapping;
121: if (ans == null)
122: ans = new JdbcJavaTypeMapping();
123: JdbcJavaTypeMapping m = (JdbcJavaTypeMapping) javaTypeMappings
124: .get(javaType);
125: if (m != null)
126: ans.copyFrom(m);
127: JdbcTypeMapping tm = typeMappings[ans.getJdbcType()
128: - FIRST_TYPE];
129: if (tm == null) {
130: throw BindingSupportImpl.getInstance().runtime(
131: "No JDBC type mapping found for: "
132: + JdbcTypes.toString(ans.getJdbcType())
133: + " (" + javaType + " " + fieldName + ")");
134: }
135: ans.copyFrom(tm);
136: return ans;
137: }
138:
139: /**
140: * If fm has a jdbcType set then use this type to fill in the other
141: * fields of fm that do not have values. Otherwise do nothing. This
142: * is used when the mapping is going to be used to modify a copy of
143: * another column.
144: */
145: public void fillMappingForJdbcType(JdbcJavaTypeMapping fm) {
146: if (fm.getJdbcType() == 0)
147: return;
148: JdbcTypeMapping tm = typeMappings[fm.getJdbcType() - FIRST_TYPE];
149: if (tm == null) {
150: throw BindingSupportImpl.getInstance().runtime(
151: "No JDBC type mapping found for: "
152: + JdbcTypes.toString(fm.getJdbcType()));
153: }
154: fm.copyFrom(tm);
155: }
156:
157: /**
158: * Get the type mapping for a JDBC type code.
159: */
160: public JdbcTypeMapping getTypeMapping(int jdbcType) {
161: return typeMappings[jdbcType - FIRST_TYPE];
162: }
163:
164: /**
165: * Get the converter factory used for the supplied JDBC type or null
166: * if none.
167: * @param jdbcType JDBC type code from java.sql.Types
168: * @see Types
169: */
170: public JdbcConverterFactory getJdbcConverterFactory(int jdbcType) {
171: JdbcTypes.toString(jdbcType);
172: JdbcTypeMapping tm = getTypeMapping(jdbcType);
173: if (tm == null) {
174: throw BindingSupportImpl.getInstance().illegalArgument(
175: "No JDBC type mapping found for: "
176: + JdbcTypes.toString(jdbcType));
177: }
178: JdbcConverterFactory ans = tm.getConverterFactory();
179: if (ans == null) {
180: throw BindingSupportImpl.getInstance().illegalArgument(
181: "No JdbcConverter found for JDBC type: "
182: + JdbcTypes.toString(jdbcType));
183: }
184: return ans;
185: }
186:
187: /**
188: * Register any enabled store specific types with the mdutils so fields of
189: * those types will be considered persistent.
190: */
191: public void registerStoreTypes(MetaDataUtils mdutils) {
192: for (Iterator i = javaTypeMappings.entrySet().iterator(); i
193: .hasNext();) {
194: Map.Entry e = (Map.Entry) i.next();
195: Class type = (Class) e.getKey();
196: JdbcJavaTypeMapping mapping = (JdbcJavaTypeMapping) e
197: .getValue();
198: if (mapping.getEnabled() != JdbcJavaTypeMapping.FALSE
199: && !mdutils.isPersistentType(type,
200:
201: Collections.EMPTY_MAP
202:
203: )) {
204: mdutils.registerStoreType(type);
205: }
206: }
207: }
208:
209: }
|