KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > mapper > mapping > RepositoryMapping


1 /*
2  * This file belongs to the XQuark distribution.
3  * Copyright (C) 2003 Universite de Versailles Saint-Quentin.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307.
18  * You can also get it at http://www.gnu.org/licenses/lgpl.html
19  *
20  * For more information on this software, see http://www.xquark.org.
21  */

22
23 package org.xquark.mapper.mapping;
24
25
26 import java.sql.SQLException JavaDoc;
27 import java.util.*;
28
29 import org.xml.sax.SAXException JavaDoc;
30 import org.xquark.mapper.RepositoryException;
31 import org.xquark.mapper.dbms.AbstractConnection;
32 import org.xquark.mapper.metadata.Repository;
33 import org.xquark.xpath.XTree;
34
35
36 /** Shared memory data structure representing an XQuark Mapping file.
37  *
38  */

39 public class RepositoryMapping extends XTree
40 implements MappingSet
41 {
42     private static final String JavaDoc RCSRevision = "$Revision: 1.1 $";
43     private static final String JavaDoc RCSName = "$Name: $";
44     
45     /**
46      *
47      */

48     //
49
// DATA
50
//
51

52     /** List used used during construction (in fact construction order,
53      * i.e. table index order).
54      */

55     private ArrayList tableMappingList = new ArrayList();
56
57     /** Array used notably when need to get table column mappings in no
58      * particular order or for direct access (in fact construction order,
59      * i.e. table index order).
60      */

61     private TableMapping[] tableMappings;
62
63     /** List used notably when need to get table column mappings in the
64      * relational table reference order.
65      */

66     private TableMapping[] mostDependantFirst;
67
68     /** List used notably when need to get table column mappings sorted by
69      * name (ascending).
70      */

71 // private List tableNameSorted;
72

73     /** Metadata for user tables referenced by mapping */
74     private HashMap tableMetadata = new HashMap();
75     
76     /** Metadata nodes for Types indexed by schema components */
77     private HashMap typeMappings = null;
78     private Repository rep;
79     
80     public RepositoryMapping(Repository rep)
81     {
82         this.rep = rep;
83     }
84     
85     public Repository getRepository()
86     {
87         return rep;
88     }
89     
90     public MappingNode addTypeNode(MappingNode node)
91     {
92         if (typeMappings == null)
93             typeMappings = new HashMap();
94         typeMappings.put(node.getSchemaComponent(), node);
95         return node; // return the created node, not the replaced returned by put (should not happen)
96
}
97     
98     public MappingNode getTypeNode(org.xquark.schema.Type type)
99     {
100         if (typeMappings == null)
101             return null;
102         return (MappingNode)typeMappings.get(type);
103     }
104     
105     public void addTableMapping(TableMapping tm)
106     {
107         tableMappingList.add(tm);
108     }
109     
110     public TableMapping getTableMapping(int index)
111     {
112         return tableMappings[index];
113     }
114     
115     public int getTableCount()
116     {
117         if (tableMappings == null)
118             return tableMappingList.size();
119         else
120             return tableMappings.length;
121     }
122     
123     /** Should overwrite the default registration
124      */

125     public void register(MappingNode wNode, Mapping mapping)
126     {
127         // update the table mapping list in scope for ascendants
128
if (mapping instanceof TableMapping)
129         {
130             for (MappingNode elt = wNode;
131             (elt != null) && elt.addMappingInScope((TableMapping)mapping);
132             elt = (MappingNode)elt.getParent());
133         }
134         // set the buildable flag and builder node
135
if (mapping instanceof ColumnMapping)
136         {
137             ColumnMapping column = (ColumnMapping)mapping;
138             if (column.getGenerator() instanceof ValueGenerator) // other are not needed by reconstruction
139
{
140                 MappingNode elt;
141                 for ( elt = wNode;
142                 (elt.getTableMappings() == null) || !elt.getTableMappings().contains(column.getTableMapping());
143                 elt = (MappingNode)elt.getParent())
144                 {
145                     elt.setBuildable(false);
146                 }
147                 int tableAncestorDepth = elt.getDepth();
148                 // Now table node has been located replace in the hierachy if the node
149
// is "upper" in the tree than the current builder.
150
for ( elt = wNode;
151                 elt.getDepth() > tableAncestorDepth; // diff 0 is default
152
elt = (MappingNode)elt.getParent())
153                 {
154                     if ((elt.getBuilder() == null) || (tableAncestorDepth < elt.getBuilder().getDepth()))
155                         elt.setBuilderDiff(elt.getDepth() - tableAncestorDepth);
156                 }
157             }
158         }
159         
160         wNode.register(mapping);
161     }
162     
163     public String JavaDoc toString()
164     {
165         String JavaDoc ret = super.toString();
166         if (typeMappings != null)
167              ret += "\nTable mappings list:\n" + tableMappings.toString();
168         return ret;
169     }
170     
171
172     /**
173      * Verify mapping does not define multiple table mapping with different
174      * join columns (used by repository not mapper).
175      * COULD BE PERFORMED ON-LINE (on register) ?
176      */

177     public void checkRedundantTables() throws RepositoryException
178     {
179         // browse the array to process doubles
180
MappingSetIterator it = new MappingSetIteratorImpl(tableMappings);
181         while (it.hasNext())
182         {
183             BaseTableMappingImpl tm = (BaseTableMappingImpl)it.next().getTableMapping();
184             
185             // if table mapping on the same table, check it is equivalent or throw an exception
186
if (!it.isTableFirstOccurence())
187             {
188                 TableMapping tf = tableMappings[it.getFirstOccurenceTableIndex()];
189                 
190                 // set the shared flag
191
tm.setTableShared();
192                 
193                 // check the join columns
194
if (!areColumnArraysEquivalent(
195                     tf.getJoinColumns(),
196                     tm.getJoinColumns()
197                     ))
198                     throw new RepositoryException(
199                         RepositoryException.NOT_ALLOWED,
200                             "Multiple mappings defined on the same table("
201                             + tm.getTableName()
202                             + ") must have the same key specification.");
203                             
204                 // check the statements can be shared
205
if (tm.isShareable() && !(
206                     areColumnArraysEquivalent(tm.getColumnMappings(), tf.getColumnMappings())
207                 && areColumnArraysEquivalent(tm.getSelectColumns(), tf.getSelectColumns())
208                 && areColumnArraysEquivalent(tm.getUpdateColumns(), tf.getUpdateColumns())))
209                     tm.setStatementsNotShareable();
210             }
211         }
212     }
213
214     /**
215      * Return an iterator that browse table mappings with join tables
216      * (unclustered) and different user tables.
217      * @return Iterator
218      */

219     public Iterator joinTableIterator()
220     {
221         return new TableIterator(true);
222     }
223     
224     ////////////////////////////////////////////////////////////////////
225
// MappingSet implementation
226
////////////////////////////////////////////////////////////////////
227
public int getMappingStatementsCount()
228     {
229         return getTableCount();
230     }
231     
232     public MappingInfo getMappingStatements(int index)
233     {
234         return getTableMapping(index);
235     }
236     
237     public MappingSetIterator getSortedTableMappingSetIterator(boolean mostDependantFirst)
238     {
239         return new MappingSetIteratorImpl(this.mostDependantFirst, !mostDependantFirst);
240     }
241     
242     public MappingSetIterator getMappingSetIterator()
243     {
244         return new MappingSetIteratorImpl(tableMappings);
245     }
246     
247     ////////////////////////////////////////////////////////////////////
248
// PACKAGE METHODS
249
////////////////////////////////////////////////////////////////////
250
void initialize(AbstractConnection conn) throws SAXException JavaDoc
251     {
252         initializeArrays(conn);
253     }
254
255     TableMetaData getTableMetaData(String JavaDoc tableName, AbstractConnection conn)
256     throws SAXException JavaDoc
257     {
258         TableMetaData ret = (TableMetaData) tableMetadata.get(tableName);
259         if (ret == null)
260         {
261             try
262             {
263                 if (conn.checkTable(tableName))
264                 {
265                     ret = new TableMetaDataImpl(tableName, conn);
266                     tableMetadata.put(tableName, ret);
267                 }
268             }
269             catch (SQLException JavaDoc ex)
270             {
271                 throw new SAXException JavaDoc(
272                     "Error while fetching table " + tableName + " metadata",
273                     ex);
274             }
275         }
276         return ret;
277     }
278     ////////////////////////////////////////////////////////////////////
279
// PRIVATE
280
////////////////////////////////////////////////////////////////////
281
private void initializeArrays(AbstractConnection conn) throws SAXException JavaDoc
282     {
283         // create table mapping array
284
tableMappings = (TableMapping[])tableMappingList.toArray(new TableMapping[tableMappingList.size()]);
285         tableMappingList = null;
286         
287
288         // initialize key dependencies
289
TableMappingImpl tm = null;
290         for (int i = 0; i < tableMappings.length; i++) {
291             tm = (TableMappingImpl)tableMappings[i];
292             // NOTE: some mapping (type mapping) may not be used and thus are not initialized
293
// but removing it now would corrupt ref index...
294
if (!tm.isInitialized())
295                 tm.initialize(conn);
296             tm.initializeDependencies();
297         }
298             
299         // create ordered table list
300
mostDependantFirst = new TableMapping[tableMappings.length];
301         System.arraycopy(tableMappings, 0, mostDependantFirst, 0, tableMappings.length);
302         Arrays.sort(mostDependantFirst, new Comparator()
303         {
304             public int compare(Object JavaDoc o1, Object JavaDoc o2)
305             {
306                 BaseTableMappingImpl tm1 = (BaseTableMappingImpl)((MappingInfo)o1).getTableMapping();
307                 BaseTableMappingImpl tm2 = (BaseTableMappingImpl)((MappingInfo)o2).getTableMapping();
308                     return tm2.getDependencies().size()
309                         - tm1.getDependencies().size();
310             }
311         });
312     }
313
314     /**
315      * This iterator only returns table mappings with join table only
316      * one time by user table.
317      *
318      */

319     private class TableIterator implements Iterator
320     {
321         MappingSetIterator iterator;
322         MappingInfo next = null;
323         boolean unclusteredOnly;
324         
325         public TableIterator(boolean unclusteredOnly)
326         {
327             iterator = new MappingSetIteratorImpl(tableMappings);
328             this.unclusteredOnly = unclusteredOnly;
329         }
330
331         public TableIterator()
332         {
333             this(false);
334         }
335
336         public boolean hasNext()
337         {
338             while (next == null && iterator.hasNext())
339             {
340                 next = iterator.next();
341                 if (!keepCondition())
342                     next = null;
343             }
344             return next != null;
345         }
346         
347         private boolean keepCondition()
348         {
349             return iterator.isTableFirstOccurence()
350             && (!unclusteredOnly || !next.getTableMapping().isClustered());
351         }
352
353         public Object JavaDoc next()
354         {
355             MappingInfo ret = null;
356             if (hasNext())
357             {
358                 ret = next;
359                 next = null;
360             }
361             return ret;
362         }
363         
364         public void remove()
365         {
366             throw new UnsupportedOperationException JavaDoc();
367         }
368
369     }
370     
371     private boolean areColumnArraysEquivalent(
372         ColumnMapping[] t1,
373         ColumnMapping[] t2)
374     {
375         boolean equivalent = true;
376         if (t1 != null && t2 != null)
377         {
378             if (t1.length != t2.length)
379                 equivalent = false;
380
381             // loop looking for difference
382
for (int j = 0; j < t2.length; j++)
383             {
384                 if (!t1[j]
385                     .getColumnName()
386                     .equals(t2[j].getColumnName()))
387                     equivalent = false;
388             }
389         }
390         else if (t1 != t2)
391             equivalent = false;
392         return equivalent;
393     }
394
395 }
396
Popular Tags