KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > versant > core > jdbc > JdbcPolyRefMetaDataBuilder


1
2 /*
3  * Copyright (c) 1998 - 2005 Versant Corporation
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  * Versant Corporation - initial API and implementation
11  */

12 package com.versant.core.jdbc;
13
14 import com.versant.core.metadata.parser.JdoExtension;
15 import com.versant.core.metadata.parser.JdoElement;
16 import com.versant.core.metadata.parser.JdoExtensionKeys;
17 import com.versant.core.metadata.MetaDataBuilder;
18 import com.versant.core.metadata.ClassMetaData;
19 import com.versant.core.metadata.ClassIdTranslator;
20 import com.versant.core.jdbc.metadata.*;
21 import com.versant.core.util.IntObjectHashMap;
22
23 import java.util.*;
24
25 import com.versant.core.common.BindingSupportImpl;
26
27 /**
28  * This will analyze meta data for a reference to any PC class from an
29  * array of extensions. It is used for polyref fields and for polymorphic link
30  * tables. Instances of this class may only be used once.
31  */

32 public class JdbcPolyRefMetaDataBuilder implements JdoExtensionKeys {
33
34     private JdbcMetaDataBuilder mdb;
35     private JdoElement context;
36     private String JavaDoc fieldName;
37     private JdbcField field;
38
39     private ArrayList colsList = new ArrayList();
40
41     private JdbcColumn classIdCol;
42     private JdbcColumn[] pkCols;
43     private JdbcColumn[] cols;
44
45     private HashSet classIdSet = new HashSet(); // to detect duplicate IDs
46

47     private boolean stringClassIds; // is at least one class-id in map not int
48

49     // ClassMetaData -> String for ID translation
50
private Map cmdToIDString = new HashMap();
51     private Map idToCmdString; // String ID -> ClassMetaData
52

53     // contains int values of class-ids if all are ints
54
private Map cmdToIDInt = new HashMap();
55     private IntObjectHashMap idToCmdInt; // int ID -> ClassMetaData
56

57     private ClassIdTranslator classIdTranslator;
58
59     public JdbcPolyRefMetaDataBuilder(JdbcMetaDataBuilder mdb,
60             JdoElement context, String JavaDoc fieldName, JdoExtension[] extensions,
61             JdbcField field) {
62         this.mdb = mdb;
63         this.context = context;
64         this.fieldName = fieldName;
65         this.field = field;
66         process(extensions);
67     }
68
69     private void process(JdoExtension[] extensions) {
70         JdoExtension classIdColExt = null;
71         if (extensions != null) {
72             int ne = extensions.length;
73             for (int i = 0; i < ne; i++) {
74                 JdoExtension e = extensions[i];
75                 switch (e.key) {
76
77                     case JDBC_CLASS_ID:
78                         if (classIdColExt != null) {
79                             throw BindingSupportImpl.getInstance().runtime(
80                                 "Only one jdbc-class-id extension is allowed\n" +
81                                 context);
82                         }
83                         classIdColExt = e;
84                         break;
85
86                     case JDBC_REF:
87                         colsList.add(mdb.createColumn(e.nested, fieldName,
88                                 Integer JavaDoc.class));
89                         break;
90
91                     case VALID_CLASS:
92                         processClassIdMapping(e);
93                         break;
94
95                     default:
96                         if (e.isJdbc()) MetaDataBuilder.throwUnexpectedExtension(e);
97                         break;
98                 }
99             }
100         }
101
102         // convert all the class-id's to ints if possible
103
try {
104             for (Iterator i = cmdToIDString.keySet().iterator(); i.hasNext(); ) {
105                 ClassMetaData key = (ClassMetaData)i.next();
106                 String JavaDoc value = (String JavaDoc)cmdToIDString.get(key);
107                 cmdToIDInt.put(key, new Integer JavaDoc(value));
108             }
109         } catch (NumberFormatException JavaDoc e) {
110             stringClassIds = true;
111         }
112
113         // get rid of empty maps and init id -> class maps
114
if (cmdToIDString.size() == 0) cmdToIDString = null;
115         if (cmdToIDInt.size() == 0) cmdToIDInt = null;
116
117         if (cmdToIDInt != null) { // build reverse map
118
idToCmdInt = new IntObjectHashMap();
119             for (Iterator i = cmdToIDInt.keySet().iterator(); i.hasNext(); ) {
120                 ClassMetaData key = (ClassMetaData)i.next();
121                 int value = ((Integer JavaDoc)cmdToIDInt.get(key)).intValue();
122                 idToCmdInt.put(value, key);
123             }
124         }
125
126         if (cmdToIDString != null) { // build reverse map
127
idToCmdString = new HashMap();
128             for (Iterator i = cmdToIDString.keySet().iterator(); i.hasNext(); ) {
129                 ClassMetaData key = (ClassMetaData)i.next();
130                 String JavaDoc value = (String JavaDoc)cmdToIDString.get(key);
131                 idToCmdString.put(value, key);
132             }
133         }
134
135         // create the translator
136
classIdTranslator = new ClassIdTranslator(field.fmd.classMetaData.jmd,
137                 stringClassIds, cmdToIDString, idToCmdString,
138                 cmdToIDInt, idToCmdInt);
139         classIdTranslator.setMessage("field " + field.fmd.getQName());
140
141         // make sure all possible classes have the same number of primary
142
// key columns if any valid-class elements were used and also get
143
// the primary key of the first class
144
JdbcColumn[] firstPk = null;
145         List cl = classIdTranslator.getClassList();
146         int n = cl.size();
147         if (n > 0) {
148             ClassMetaData first = (ClassMetaData)cl.get(0);
149             firstPk = ((JdbcClass)first.storeClass).table.pk;
150             for (int i = 1; i < n; i++) {
151                 ClassMetaData cmd = (ClassMetaData)cl.get(i);
152                 int len = ((JdbcClass)cmd.storeClass).table.pk.length;
153                 if (len != firstPk.length) {
154                     throw BindingSupportImpl.getInstance().runtime(
155                         "All valid classes must have the same number of " +
156                         "primary key columns\n" +
157                         first + " has " + firstPk.length + "\n" +
158                         cmd + " has " + len + "\n" +
159                         field.fmd.jdoField.getContext());
160                 }
161             }
162         }
163
164         // generate the classIdCol
165
classIdCol = mdb.createColumn(classIdColExt == null ? null : classIdColExt.nested,
166                 fieldName, stringClassIds ? String JavaDoc.class : Integer JavaDoc.class);
167
168         // generate primary key column(s) if none specified
169
if (colsList.isEmpty()) {
170             if (firstPk != null) {
171                 for (int i = 0; i < firstPk.length; i++) {
172                     JdbcColumn c = mdb.createColumn(null, firstPk[i]);
173                     c.pk = false;
174                     colsList.add(c);
175                 }
176             } else {
177                 colsList.add(mdb.createColumn(null, fieldName, Integer JavaDoc.class));
178             }
179         } else if (firstPk != null && colsList.size() != firstPk.length) {
180             throw BindingSupportImpl.getInstance().runtime(
181                 "Mismatched reference column(s): " +
182                 colsList.size() + " reference column(s) defined but " +
183                 "valid classes have " + firstPk.length +
184                 " primary key column(s)\n" +
185                 field.fmd.jdoField.getContext());
186         }
187
188         pkCols = new JdbcColumn[colsList.size()];
189         colsList.toArray(pkCols);
190         colsList.add(0, classIdCol);
191         cols = new JdbcColumn[colsList.size()];
192         colsList.toArray(cols);
193     }
194
195     public JdbcColumn getClassIdCol() {
196         return classIdCol;
197     }
198
199     public JdbcColumn[] getPkCols() {
200         return pkCols;
201     }
202
203     public JdbcColumn[] getCols() {
204         return cols;
205     }
206
207     public ArrayList getColsList() {
208         return colsList;
209     }
210
211     /**
212      * Get a translator for the class-id's of this field.
213      */

214     public ClassIdTranslator getClassIdTranslator() {
215         return classIdTranslator;
216     }
217
218     private void processClassIdMapping(JdoExtension e) {
219         String JavaDoc value = e.getString();
220         int i = value.indexOf('=');
221         String JavaDoc cname = i < 0 ? value : value.substring(0, i);
222         String JavaDoc id = i < 0 ? null : value.substring(i + 1);
223         ClassMetaData key = mdb.getJmd().getClassMetaData(
224                 field.fmd.classMetaData, cname);
225         if (key == null) {
226             throw BindingSupportImpl.getInstance().runtime("No persistent class found for '" +
227                 cname + "': " + e + "\n" + e.getContext());
228         }
229         if (cmdToIDString.containsKey(key)) {
230             throw BindingSupportImpl.getInstance().runtime("Duplicate class in mapping '" +
231                 cname + "': " + e + "\n" + e.getContext());
232         }
233         if (id == null || id.length() == 0) id = Integer.toString(key.classId);
234         if (classIdSet.contains(id)) {
235             throw BindingSupportImpl.getInstance().runtime("Duplicate class-id in mapping '" +
236                 id + "': " + e + "\n" + e.getContext());
237         }
238         cmdToIDString.put(key, id);
239         classIdSet.add(id);
240     }
241
242 }
243
Popular Tags