KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ojb > broker > ant > PreparedModel


1 package org.apache.ojb.broker.ant;
2
3 /* Copyright 2004-2005 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */

17
18 import java.util.ArrayList JavaDoc;
19 import java.util.Arrays JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.HashSet JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.List JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.Set JavaDoc;
26 import java.util.TreeMap JavaDoc;
27
28 import org.apache.commons.beanutils.DynaBean;
29 import org.apache.ddlutils.model.Column;
30 import org.apache.ddlutils.model.Database;
31 import org.apache.ddlutils.model.Table;
32 import org.apache.ojb.broker.metadata.ClassDescriptor;
33 import org.apache.ojb.broker.metadata.CollectionDescriptor;
34 import org.apache.ojb.broker.metadata.DescriptorRepository;
35 import org.apache.ojb.broker.metadata.FieldDescriptor;
36
37 /**
38  * Provides a model derived from {@link org.apache.ojb.broker.metadata.DescriptorRepository} that
39  * is preprocessed for data handling (inserting data, generating data dtd).
40  *
41  * @author Thomas Dudziak
42  */

43 public class PreparedModel
44 {
45     /** The database model. */
46     private Database _schema;
47     /** Maps dtd elements to tables */
48     private TreeMap JavaDoc _elementToTable = new TreeMap JavaDoc();
49     /** Maps dtd elements to lists of class descriptors (which all map to the same table) */
50     private HashMap JavaDoc _elementToClassDescriptors = new HashMap JavaDoc();
51     /** Maps dtd elements to colum maps which in turn map attribute names to columns */
52     private HashMap JavaDoc _elementToColumnMap = new HashMap JavaDoc();
53     /** Maps dtd elements to maps that specify which attributes are required */
54     private HashMap JavaDoc _elementToRequiredAttributesMap = new HashMap JavaDoc();
55
56     public PreparedModel(DescriptorRepository model, Database schema)
57     {
58         _schema = schema;
59         prepareModel(model);
60     }
61
62     public Iterator JavaDoc getElementNames()
63     {
64         return _elementToTable.keySet().iterator();
65     }
66
67     public Iterator JavaDoc getAttributeNames(String JavaDoc elementName)
68     {
69         Map JavaDoc columns = getColumnsFor(elementName);
70
71         return columns == null ? null : columns.keySet().iterator();
72     }
73
74     public Map JavaDoc getRequiredAttributes(String JavaDoc elementName)
75     {
76         return (Map JavaDoc)_elementToRequiredAttributesMap.get(elementName);
77     }
78
79     public boolean isRequired(String JavaDoc elementName, String JavaDoc attributeName)
80     {
81         Map JavaDoc requiredAttributes = getRequiredAttributes(elementName);
82
83         if (requiredAttributes == null)
84         {
85             return false;
86         }
87         else
88         {
89             Boolean JavaDoc status = (Boolean JavaDoc)requiredAttributes.get(attributeName);
90
91             return status == null ? false : status.booleanValue();
92         }
93     }
94
95     public Table getTableFor(String JavaDoc elementName)
96     {
97         return (Table)_elementToTable.get(elementName);
98     }
99
100     /**
101      * Creates a dyna bean for the table associated to the given element.
102      *
103      * @param elementName The element name
104      * @return The dyna bean
105      */

106     public DynaBean createBeanFor(String JavaDoc elementName)
107     {
108         return _schema.createDynaBeanFor(getTableFor(elementName));
109     }
110     
111     public List JavaDoc getClassDescriptorsMappingTo(String JavaDoc elementName)
112     {
113         return (List JavaDoc)_elementToClassDescriptors.get(elementName);
114     }
115
116     public Map JavaDoc getColumnsFor(String JavaDoc elementName)
117     {
118         return (Map JavaDoc)_elementToColumnMap.get(elementName);
119     }
120
121     public Column getColumnFor(String JavaDoc elementName, String JavaDoc attrName)
122     {
123         Map JavaDoc columns = getColumnsFor(elementName);
124
125         if (columns == null)
126         {
127             return null;
128         }
129         else
130         {
131             return (Column)columns.get(attrName);
132         }
133     }
134
135     /**
136      * Prepares a representation of the model that is easier accessible for our purposes.
137      *
138      * @param model The original model
139      * @return The model representation
140      */

141     private void prepareModel(DescriptorRepository model)
142     {
143         TreeMap JavaDoc result = new TreeMap JavaDoc();
144
145         for (Iterator JavaDoc it = model.getDescriptorTable().values().iterator(); it.hasNext();)
146         {
147             ClassDescriptor classDesc = (ClassDescriptor)it.next();
148
149             if (classDesc.getFullTableName() == null)
150             {
151                 // not mapped to a database table
152
continue;
153             }
154
155             String JavaDoc elementName = getElementName(classDesc);
156             Table mappedTable = getTableFor(elementName);
157             Map JavaDoc columnsMap = getColumnsFor(elementName);
158             Map JavaDoc requiredAttributes = getRequiredAttributes(elementName);
159             List JavaDoc classDescs = getClassDescriptorsMappingTo(elementName);
160
161             if (mappedTable == null)
162             {
163                 mappedTable = _schema.findTable(classDesc.getFullTableName());
164                 if (mappedTable == null)
165                 {
166                     continue;
167                 }
168                 columnsMap = new TreeMap JavaDoc();
169                 requiredAttributes = new HashMap JavaDoc();
170                 classDescs = new ArrayList JavaDoc();
171                 _elementToTable.put(elementName, mappedTable);
172                 _elementToClassDescriptors.put(elementName, classDescs);
173                 _elementToColumnMap.put(elementName, columnsMap);
174                 _elementToRequiredAttributesMap.put(elementName, requiredAttributes);
175             }
176             classDescs.add(classDesc);
177             extractAttributes(classDesc, mappedTable, columnsMap, requiredAttributes);
178         }
179         extractIndirectionTables(model, _schema);
180     }
181
182     private void extractAttributes(ClassDescriptor classDesc, Table mappedTable, Map JavaDoc columnsMap, Map JavaDoc requiredColumnsMap)
183     {
184         FieldDescriptor[] fieldDescs = classDesc.getFieldDescriptions();
185
186         if (fieldDescs != null)
187         {
188             for (int idx = 0; idx < fieldDescs.length; idx++)
189             {
190                 Column column = mappedTable.findColumn(fieldDescs[idx].getColumnName());
191
192                 if (column != null)
193                 {
194                     // we'll check whether another field (of not necessarily the same name)
195
// already maps to this column; if this is the case, we're ignoring
196
// this field
197
boolean alreadyMapped = false;
198
199                     for (Iterator JavaDoc mappedColumnsIt = columnsMap.values().iterator(); mappedColumnsIt.hasNext();)
200                     {
201                         if (column.equals(mappedColumnsIt.next()))
202                         {
203                             alreadyMapped = true;
204                             break;
205                         }
206                     }
207                     if (!alreadyMapped)
208                     {
209                         String JavaDoc shortAttrName = getShortAttributeName(fieldDescs[idx].getAttributeName());
210         
211                         columnsMap.put(shortAttrName, column);
212                         requiredColumnsMap.put(shortAttrName,
213                                                fieldDescs[idx].isPrimaryKey() ? Boolean.TRUE : Boolean.FALSE);
214                     }
215                 }
216             }
217         }
218     }
219
220     /**
221      * Extracts indirection tables from the given class descriptor, and adds elements
222      * for them. In contrast to normal elements, for indirection tables the element name
223      * matches the table name, and the attribute names match the column names.
224      *
225      * @param model The model
226      * @param elements The elements
227      */

228     private void extractIndirectionTables(DescriptorRepository model, Database schema)
229     {
230         HashMap JavaDoc indirectionTables = new HashMap JavaDoc();
231
232         // first we gather all participants for each m:n relationship
233
for (Iterator JavaDoc classDescIt = model.getDescriptorTable().values().iterator(); classDescIt.hasNext();)
234         {
235             ClassDescriptor classDesc = (ClassDescriptor)classDescIt.next();
236
237             for (Iterator JavaDoc collDescIt = classDesc.getCollectionDescriptors().iterator(); collDescIt.hasNext();)
238             {
239                 CollectionDescriptor collDesc = (CollectionDescriptor)collDescIt.next();
240                 String JavaDoc indirTable = collDesc.getIndirectionTable();
241
242                 if ((indirTable != null) && (indirTable.length() > 0))
243                 {
244                     Set JavaDoc columns = (Set JavaDoc)indirectionTables.get(indirTable);
245
246                     if (columns == null)
247                     {
248                         columns = new HashSet JavaDoc();
249                         indirectionTables.put(indirTable, columns);
250                     }
251                     columns.addAll(Arrays.asList(collDesc.getFksToThisClass()));
252                     columns.addAll(Arrays.asList(collDesc.getFksToItemClass()));
253                 }
254             }
255         }
256         if (indirectionTables.isEmpty())
257         {
258             // nothing to do
259
return;
260         }
261
262         for (Iterator JavaDoc it = indirectionTables.keySet().iterator(); it.hasNext();)
263         {
264             String JavaDoc tableName = (String JavaDoc)it.next();
265             Set JavaDoc columns = (Set JavaDoc)indirectionTables.get(tableName);
266             String JavaDoc elementName = tableName;
267
268             for (Iterator JavaDoc classDescIt = model.getDescriptorTable().values().iterator(); classDescIt.hasNext();)
269             {
270                 ClassDescriptor classDesc = (ClassDescriptor)classDescIt.next();
271
272                 if (tableName.equals(classDesc.getFullTableName()))
273                 {
274                     elementName = getElementName(classDesc);
275
276                     FieldDescriptor[] fieldDescs = classDesc.getFieldDescriptions();
277
278                     if (fieldDescs != null)
279                     {
280                         for (int idx = 0; idx < fieldDescs.length; idx++)
281                         {
282                             columns.remove(fieldDescs[idx].getColumnName());
283                         }
284                     }
285                 }
286             }
287
288             Table mappedTable = getTableFor(elementName);
289             Map JavaDoc columnsMap = getColumnsFor(elementName);
290             Map JavaDoc requiredAttributes = getRequiredAttributes(elementName);
291     
292             if (mappedTable == null)
293             {
294                 mappedTable = schema.findTable(elementName);
295                 if (mappedTable == null)
296                 {
297                     continue;
298                 }
299                 columnsMap = new TreeMap JavaDoc();
300                 requiredAttributes = new HashMap JavaDoc();
301                 _elementToTable.put(elementName, mappedTable);
302                 _elementToColumnMap.put(elementName, columnsMap);
303                 _elementToRequiredAttributesMap.put(elementName, requiredAttributes);
304             }
305             for (Iterator JavaDoc columnIt = columns.iterator(); columnIt.hasNext();)
306             {
307                 String JavaDoc columnName = (String JavaDoc)columnIt.next();
308                 Column column = mappedTable.findColumn(columnName);
309
310                 if (column != null)
311                 {
312                     columnsMap.put(columnName, column);
313                     requiredAttributes.put(columnName, Boolean.TRUE);
314                 }
315             }
316         }
317     }
318
319     /**
320      * Returns the element name for the class descriptor which is the adjusted short (unqualified) class
321      * name. Also takes care that the element name does not clash with another class of the same short
322      * name that maps to a different table though.
323      *
324      * @param classDesc The class descriptor
325      * @return The element name
326      */

327     private String JavaDoc getElementName(ClassDescriptor classDesc)
328     {
329         String JavaDoc elementName = classDesc.getClassNameOfObject().replace('$', '_');
330
331         elementName = elementName.substring(elementName.lastIndexOf('.') + 1);
332
333         Table table = getTableFor(elementName);
334         int suffix = 0;
335
336         while ((table != null) && !table.getName().equals(classDesc.getFullTableName()))
337         {
338             ++suffix;
339             table = getTableFor(elementName + "-" + suffix);
340         }
341         if (suffix > 0)
342         {
343             elementName += "-" + suffix;
344         }
345
346         return elementName;
347     }
348
349     /**
350      * Adjusts the local attribute name (the part after the last '::' for nested fields).
351      *
352      * @param attrName The original attribute name
353      * @return The local attribute name
354      */

355     private String JavaDoc getShortAttributeName(String JavaDoc attrName)
356     {
357         return attrName.substring(attrName.lastIndexOf(':') + 1);
358     }
359 }
360
Popular Tags