KickJava   Java API By Example, From Geeks To Geeks.

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


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 import java.io.File JavaDoc;
26 import java.lang.reflect.Constructor JavaDoc;
27 import java.net.MalformedURLException JavaDoc;
28 import java.net.URL JavaDoc;
29 import java.sql.SQLException JavaDoc;
30 import java.util.*;
31
32 import org.xml.sax.*;
33 import org.xquark.mapping.CompilationContext;
34 import org.xquark.mapping.Generator;
35 import org.xquark.mapping.UserGenerator;
36 import org.xquark.mapper.dbms.AbstractConnection;
37 import org.xquark.mapper.metadata.RepositoryConstants;
38 import org.xquark.mapper.util.RepositoryProperties;
39 import org.xquark.schema.*;
40 import org.xquark.util.DefaultElementHandler;
41 import org.xquark.util.ElementHandler;
42 import org.xquark.util.SAXLoader;
43 import org.xquark.xml.xdbc.XMLErrorHandler;
44 import org.xquark.xpath.NodeKind;
45 import org.xquark.xpath.XNode;
46
47 /** This class is responsible for building the memory reprezentation of the
48  * mapping (RepositoryMapping) from a mapping file.
49  * @see org.xquark.mapper.metadata.RepositoryMapping
50  */

51 public class Loader extends SAXLoader implements MappingConstants
52 {
53     private static final String JavaDoc RCSRevision = "$Revision: 1.7 $";
54     private static final String JavaDoc RCSName = "$Name: $";
55
56     private RepositoryMapping colMapping =null;
57     private MappingFactory factory;
58     private XMLReader reader;
59     private AbstractConnection conn;
60     private SchemaManager manager;
61     /** Used to load user generators */
62     private ClassLoader JavaDoc classLoader = null;
63     private boolean generate =false;
64     private String JavaDoc version ="1.0";
65     private BuilderMappingContext context =null;
66     private Type currentType = null;
67     private List scope = new ArrayList();
68     /** Type Mappings */
69     private String JavaDoc currentNamedMap = null; // contains the current named mapping
70
private HashMap namedMappings = new HashMap(); // {name, [scopeItem1, scopeItem2, ...]}
71
/* If not null, warning are sent to it */
72     private XMLErrorHandler messageHandler = null;
73     /* This flag is used to desactivate OID tables in mapping for mapper */
74     private boolean userTablesOnly = false;
75
76     /** Constructor
77      * @param reader Parser used to analyse mapping file.
78      * @param conn JDBC connection used to retrieve database metadata.
79      * @param generate If true, mapping is loaded even if relational tables
80      * are not present : mapping is loaded for table generation.
81      * If false, table existence must be verified.
82      */

83     public Loader(
84         XMLReader reader,
85         AbstractConnection conn,
86         SchemaManager manager,
87         boolean generate) {
88         this(reader, conn, manager, null, generate);
89     }
90
91     public Loader(
92         XMLReader reader,
93         AbstractConnection conn,
94         SchemaManager manager,
95         ClassLoader JavaDoc loader,
96         boolean generate) {
97             super(null);
98             setElementHandler(new MappingHandler());
99             this.reader = reader;
100             this.conn = conn;
101             this.manager = manager;
102             this.generate = generate;
103             if (loader == null)
104                 classLoader = getClass().getClassLoader();
105             else
106                 classLoader = loader;
107         }
108     
109     public RepositoryMapping load(InputSource source, MappingFactory factory, boolean userTablesOnly)
110     throws java.io.IOException JavaDoc, SAXException, SQLException JavaDoc
111     {
112         return load(source, factory, null, userTablesOnly);
113     }
114             
115     public RepositoryMapping load(InputSource source, MappingFactory factory,
116             XMLErrorHandler messageHandler, boolean userTablesOnly)
117     throws java.io.IOException JavaDoc, SAXException, SQLException JavaDoc
118     {
119         this.colMapping = (RepositoryMapping)factory.getTree();
120         this.factory = factory;
121         this.messageHandler = messageHandler;
122         this.userTablesOnly = userTablesOnly;
123         currentType = null;
124         scope.clear();
125         namedMappings.clear();
126         reader.setContentHandler(this);
127         reader.parse(source);
128         colMapping.initialize(conn);
129         return colMapping;
130     }
131
132     private void notifyUnknownElement(String JavaDoc uri, String JavaDoc name)
133     throws SAXException
134     {
135         throw new SAXParseException("Syntax error : the element \"" + name
136                                + "\" with namespace \"" + uri + "\""
137                                + " is not part of the mapping language.",
138                                getDocumentLocator());
139     }
140
141     private boolean isMappingNamespace(String JavaDoc uri) {
142         return BRIDGE_MAPPING_URI.equals(uri)
143             || BRIDGE_MAPPING_URI_1_0.equals(uri)
144             || MAPPING_URI.equals(uri);
145     }
146
147     private void initMapping(Attributes atts) throws SAXException
148     {
149         context = new BuilderMappingContext(factory); // TO MOVE adding a reset
150
// to context ?
151
String JavaDoc ver = atts.getValue("", VERSION_ATTR);
152         if (ver != null)
153             version = ver;
154         URL JavaDoc base = null;
155         String JavaDoc systemId = getDocumentLocator().getSystemId();
156         if (systemId != null) {
157             try {
158                 base = new URL JavaDoc(systemId);
159             } catch (MalformedURLException JavaDoc ex) {
160                 // should not happen
161
}
162         }
163         String JavaDoc schemaLocations = atts.getValue("", SCHEMA_LOCATION_ATTR);
164         if (schemaLocations == null) {
165             schemaLocations = atts.getValue("", NO_NS_SCHEMA_LOCATION_ATTR);
166             if (schemaLocations != null)
167                 manager.addSchemaLocation(null, resolveSchemaURI(schemaLocations, base));
168         }
169         else {
170             StringTokenizer tok = new StringTokenizer(schemaLocations);
171             while (tok.hasMoreTokens()) {
172                 String JavaDoc ns = tok.nextToken();
173                 if (!tok.hasMoreTokens()) {
174                     throw new SAXParseException("Odd number of values in schemaLocation attribute: "
175                             + schemaLocations, getDocumentLocator());
176                 }
177                 manager.addSchemaLocation(ns, resolveSchemaURI(tok.nextToken(), base));
178             }
179         }
180     }
181
182     private String JavaDoc resolveSchemaURI(String JavaDoc loc, URL JavaDoc base) throws SAXParseException {
183         URL JavaDoc uri = null;
184         try {
185             if (base == null) {
186                 File JavaDoc wDir = new File JavaDoc(".");
187                 try {
188                     base = new URL JavaDoc(wDir.toURL().toExternalForm());
189                 } catch (MalformedURLException JavaDoc ex) {
190                     // no op : try without base
191
}
192                 uri = new URL JavaDoc(base, loc);
193             } else
194                 uri = new URL JavaDoc(base, loc);
195         } catch (MalformedURLException JavaDoc ex) {
196             throw new SAXParseException(
197                     "The location '"
198                             + loc
199                             + "' is malformed or it is relative and your input source does not provide a base URI.",
200                     getDocumentLocator());
201             // if invalid URI, ignore it
202
}
203         return uri.toString();
204     }
205     
206     private String JavaDoc resolvePrefix(String JavaDoc qname) throws SAXException {
207         String JavaDoc prefix = "";
208         int index = qname.indexOf(':');
209         if (index > 0) prefix = qname.substring(0, index);
210         String JavaDoc ns = getPrefixMapping(prefix);
211         if (ns == null && !prefix.equals(""))
212         throw new SAXParseException("Unknown namespace prefix " + prefix, getDocumentLocator());
213         return ns;
214     }
215
216     private String JavaDoc getLocalName(String JavaDoc qname) {
217         int index = qname.indexOf(':');
218         if (index > 0) return qname.substring(index+1);
219         else return qname;
220     }
221
222     private String JavaDoc getTableNamePart(String JavaDoc columnName, TableMappingImpl defaultTable) throws SAXException
223     {
224         String JavaDoc tablePart;
225         int index = columnName.lastIndexOf('.');
226         if (index != -1)
227             return columnName.substring(0, index);
228         else
229         {
230             TableMappingImpl tableMapping;
231             if (defaultTable == null) {
232                 tableMapping = getCurrentTableMapping();
233                 if (tableMapping == null)
234                     throw new SAXParseException("No table name is specified in '" + columnName
235                         + "' column name specification and no default table mapping was encountered.",
236                         getDocumentLocator());
237             }
238             else
239                 tableMapping = defaultTable;
240                 
241             return tableMapping.getTableName();
242         }
243     }
244
245     private String JavaDoc getTableNamePart(String JavaDoc columnName) throws SAXException
246     {
247         return getTableNamePart(columnName, null);
248     }
249
250     private String JavaDoc getColumnNamePart(String JavaDoc columnName) throws SAXException {
251         int index = columnName.lastIndexOf('.');
252         if (index == -1)
253             return columnName;
254         else
255             return columnName.substring(index+1);
256     }
257
258     private String JavaDoc checkColumnName(String JavaDoc columnName) throws SAXException {
259         return checkColumnName(columnName, null);
260     }
261
262     private String JavaDoc checkColumnName(String JavaDoc columnName, TableMappingImpl tm)
263     throws SAXException {
264         String JavaDoc tableName = getTableNamePart(columnName, tm);
265         columnName = getColumnNamePart(columnName);
266         if (tm == null)
267             tm = findMappingInScope(tableName);
268         else if (!tm.getTableName().equals(tableName))
269             throw new SAXParseException(
270                 "Column mapping cannot be defined here for table " + tableName,
271                 getDocumentLocator());
272         if (tm == null)
273             throw new SAXParseException(
274                 "Table " + tableName + " is not in scope",
275                 getDocumentLocator());
276         TableMetaData meta = tm.getMetaData();
277         if (meta != null && meta.getColumnMetaData(columnName) == null)
278             throw new SAXParseException(
279                 "Column "
280                     + columnName
281                     + " is not a column of table "
282                     + tableName,
283                 getDocumentLocator());
284         return columnName;
285     }
286
287     private ColumnMapping checkColumnRef(
288         String JavaDoc columnName,
289         TableMappingImpl tm,
290         List refChildTableMappings)
291         throws SAXException {
292         
293         String JavaDoc tableName = getTableNamePart(columnName);
294         columnName = getColumnNamePart(columnName);
295         // look in inner mapping first
296
if (tm == null && refChildTableMappings != null) {
297             int len = refChildTableMappings.size();
298             TableMappingImpl myTm = null;
299             for (int i = 0; i < len; i++) {
300                 myTm = (TableMappingImpl)refChildTableMappings.get(i);
301                 if (myTm.getTableName().equals(tableName))
302                     tm = myTm;
303             }
304         }
305         // then in scope
306
if (tm == null)
307             tm = findMappingInScope(tableName);
308         if (tm == null)
309             throw new SAXParseException(
310                 "Table " + tableName + " is not in scope",
311                 getDocumentLocator());
312         else if (!tm.getTableName().equals(tableName))
313             throw new SAXParseException(
314                 "Column mapping does not refer to table " + tableName,
315                 getDocumentLocator());
316
317         ColumnMapping cm = tm.getColumnMapping(columnName);
318         if (cm == null)
319             throw new SAXParseException(
320                 "Unknown column " + columnName + " in table " + tableName,
321                 getDocumentLocator());
322         return cm;
323     }
324
325     private int getAction(Attributes atts) throws SAXException
326     {
327         String JavaDoc actionName = atts.getValue("", ACTION_ATTR);
328         int action = INSERT;
329         if (actionName != null)
330         {
331             if (actionName.equals(INSERT_VALUE)) action = INSERT;
332             else if (actionName.equals(CHECK_VALUE)) action = CHECK;
333             else if (actionName.equals(UPDATE_VALUE)) action = UPDATE;
334             else if (actionName.equals(SELECT_VALUE)) action = SELECT;
335             else
336             throw new SAXParseException("Illegal action value: "+actionName,
337                 getDocumentLocator());
338         }
339         return action;
340     }
341     private int getBatchSize(Attributes atts) throws SAXException
342     {
343         int batchSize = RepositoryProperties.getIntProperty(RepositoryConstants.CONF_USER_BATCHSIZE);
344         String JavaDoc size = atts.getValue("", BATCH_SIZE_ATTR);
345         if (size != null)
346             batchSize = Integer.parseInt(size);
347         return batchSize;
348     }
349
350     /** Process key and select attributes for a column mapping building
351      * the role property for column mapping.
352      */

353     private int getRole(Attributes atts,int def) throws SAXException
354     {
355         int role = def;
356         String JavaDoc inKey = atts.getValue("", IN_KEY_ATTR);
357         if (inKey != null)
358         {
359             if (inKey.equals(TRUE_VALUE) || inKey.equals(TRUE_NUM_VALUE)) role |= KEY_ROLE;
360             else if (inKey.equals(FALSE_VALUE) || inKey.equals(FALSE_NUM_VALUE)) role &= ~KEY_ROLE;
361             else
362             throw new SAXParseException("Illegal value: "+inKey+" in inKey attribute", getDocumentLocator());
363         }
364         String JavaDoc inSelect = atts.getValue("", IN_SELECT_ATTR);
365         if (inSelect != null)
366         {
367             if (inSelect.equals(TRUE_VALUE) || inSelect.equals(TRUE_NUM_VALUE))
368                 role |= SELECT_ROLE;
369             else if (inSelect.equals(FALSE_VALUE) || inSelect.equals(FALSE_NUM_VALUE))
370                 role &= ~SELECT_ROLE;
371             else
372                 throw new SAXParseException("Illegal value: " + inSelect + " in inSelect attribute",
373                     getDocumentLocator());
374         }
375         return role;
376     }
377
378     private ElementDeclaration getElementDeclaration(String JavaDoc elementName)
379     throws SAXException
380     {
381         if (elementName == null)
382         throw new SAXParseException("Missing name attribute in element mapping declaration",
383             getDocumentLocator());
384         /* Look in the ElementDeclaration stack if present*/
385         String JavaDoc namespace = resolvePrefix(elementName);
386         String JavaDoc localName = getLocalName(elementName);
387         ElementDeclaration decl = null;
388         /* if the element corresponds to a complex type, look for the element in the complex type */
389         if (context.isEmpty() && (currentType != null))
390             decl = currentType.getElementDeclaration(namespace, localName);
391         if (decl == null)
392             decl = context.getElementDeclaration(namespace, localName);
393         if (decl == null) {
394             if (manager.getSchema(namespace) == null)
395                 throw new SAXParseException("Schema "+ (namespace == null ?
396                         "":"for namespace '" + namespace + "' ")
397                         + "could not be loaded.", getDocumentLocator());
398             else
399                 throw new SAXParseException("Unknown element '" + elementName
400                     +"' in element mapping declaration", getDocumentLocator());
401
402         }
403         return decl;
404     }
405
406     private AttributeDeclaration getAttributeDeclaration(String JavaDoc attrName) throws SAXException
407     {
408         if (attrName == null)
409         throw new SAXParseException("Missing name attribute in attribute mapping declaration",
410             getDocumentLocator());
411         String JavaDoc namespace = resolvePrefix(attrName);
412         String JavaDoc localName = getLocalName(attrName);
413         AttributeDeclaration decl = null;
414         if (context.isEmpty() && (currentType != null))
415             decl = currentType.getAttributeDeclaration(namespace, localName);
416         if (decl == null)
417             decl = context.getAttributeDeclaration(namespace, localName);
418         if (decl == null) {
419             if (manager.getSchema(namespace) == null)
420                 throw new SAXParseException("Schema "+ (namespace == null ?
421                         "":"for namespace '" + namespace + "' ")
422                         + "could not be loaded.", getDocumentLocator());
423             else
424                 throw new SAXParseException("Unknown attribute '" + attrName
425                     +"' in attribute mapping declaration", getDocumentLocator());
426         }
427         return decl;
428     }
429
430     private Generator getUserGenerator(String JavaDoc genClass, String JavaDoc table, String JavaDoc column) throws SAXException
431     {
432         try {
433             Class JavaDoc generatorClass = Class.forName(genClass, true, classLoader);
434             // check the class implements the generator interface
435

436             Class JavaDoc[] interfaces = generatorClass.getInterfaces();
437             int i = 0;
438             for (; i < interfaces.length && interfaces[i] != UserGenerator.class; i++);
439             if (i == interfaces.length)
440                 throw new SAXParseException("Class '" + genClass
441                 + "' is not an UserGenerator instance", getDocumentLocator());
442                 
443             // get the constructor with compilation context if exist
444
Generator gen = null;
445             try {
446                 Constructor JavaDoc constructor = generatorClass.getConstructor(
447                     new Class JavaDoc[] {CompilationContext.class});
448                 gen = (Generator)constructor.newInstance(
449                     new Object JavaDoc[] {buildCompilationContext(table, column)});
450             }
451             catch (NoSuchMethodException JavaDoc e) {
452                 // try the default constructor
453
gen = (Generator)generatorClass.newInstance();
454             }
455             return gen;
456         }
457         catch (ClassNotFoundException JavaDoc ex1) {
458             throw new SAXParseException("Generator class '"+genClass+"' not found",
459                 getDocumentLocator(), ex1);
460         }
461         catch (IllegalAccessException JavaDoc ex2) {
462             throw new SAXParseException("Could not access constructor in generator class "
463             + genClass, getDocumentLocator(), ex2);
464         }
465         catch (InstantiationException JavaDoc ex3) {
466             throw new SAXParseException("Instantiation of generator class '"
467             + genClass + "' failed", getDocumentLocator(), ex3);
468         }
469         catch (ClassCastException JavaDoc ex4) {
470             throw new SAXParseException("Generator class '"+genClass
471             +"' does not implement the interface org.xquark.xml.mapping.Generator",
472             getDocumentLocator(), ex4);
473         } catch (Exception JavaDoc ex) {
474             throw new SAXParseException("Failed to load generator class " + genClass
475             , getDocumentLocator(), ex);
476         }
477     }
478
479     private CompilationContext buildCompilationContext(String JavaDoc table, String JavaDoc column) {
480         CompilationContext ret = new CompilationContext();
481         ret.put(CompilationContext.TABLE_NAME, table);
482         ret.put(CompilationContext.COLUMN_NAME, column);
483         ret.put(CompilationContext.DBMS_TYPE, String.valueOf(conn.getDBMSType()));
484         ret.put(CompilationContext.USE_QUOTES_4_DDL, String.valueOf(conn.useDoubleQuotes4DDLNames()));
485         return ret;
486     }
487
488     private Generator getValueGenerator(Declaration decl) throws SAXException {
489         return getValueGenerator(decl.getType());
490     }
491     private Generator getValueGenerator(Type type) throws SAXException
492     {
493         if (!hasChararacterData(type))
494             throw new SAXParseException(
495             "Cannot reference $NodeValue in column mapping within an XML node without character data.",
496             getDocumentLocator());
497
498         SimpleType simple = type.getValueType();
499         if (simple != null)
500             return new ValueGenerator();
501         
502         throw new SAXParseException(
503                 "Cannot reference $NodeValue in complex element mapping",
504                 getDocumentLocator());
505     }
506     
507     private boolean hasChararacterData(Type type) {
508         boolean ret = true;
509         if (type instanceof ComplexType)
510         {
511             int contentType = ((ComplexType)type).getContentType();
512             if (contentType == SchemaConstants.ELEMENT_ONLY || contentType == SchemaConstants.EMPTY)
513                 ret = false;
514         } // else simple type
515

516         return ret;
517     }
518     
519     private Generator getSystemVariableGenerator(String JavaDoc source, Type type) throws SAXException
520     {
521         if (source.equals(VALUE_VALUE))
522             return getValueGenerator(type);
523         else
524         {
525             Generator generator = SystemVariableGenerator.createGenerator(source);
526             if (generator == null)
527                 throw new SAXParseException("Unknown system variable " + source
528                 + " in column mapping declaration", getDocumentLocator());
529             return generator;
530         }
531     }
532
533     /* used for complexType table mapping only */
534     private TableMappingImpl buildTypeTableMapping(Attributes atts) throws SAXException
535     {
536         String JavaDoc typeName = atts.getValue("", TYPE_ATTR);
537         if (typeName == null)
538             throw new SAXParseException("Missing type attribute in type mapping specification",
539                 getDocumentLocator());
540         String JavaDoc namespace = resolvePrefix(typeName);
541         Type type = context.createTypeMapping(namespace, getLocalName(typeName)); // Update the schema context (create a root node for type)
542

543         if (type == null)
544             throw new SAXParseException("Unknown type " + typeName
545                 + " in mapping declaration", getDocumentLocator());
546         String JavaDoc name = atts.getValue("", NAME_ATTR);
547         if (name == null || name.length() == 0)
548             throw new SAXParseException("Missing name in mapping declaration",
549                     getDocumentLocator());
550         TableMappingImpl res = buildTableMapping(type, atts);
551         currentNamedMap = name;
552         List typeScope = new ArrayList();
553         typeScope.add(pushScope(res));
554         namedMappings.put(name, typeScope); // put the last Table mapping encountered as the first to consider (push)
555
return res;
556     }
557
558     private TableMappingImpl buildTableMapping(SchemaComponent comp,Attributes atts)
559     throws SAXException
560     {
561         TableMappingImpl result;
562         String JavaDoc tableName = atts.getValue("", TABLE_ATTR);
563         if (tableName == null || tableName.length() == 0)
564             throw new SAXParseException("Missing table name in mapping declaration",
565                 getDocumentLocator());
566         int action = getAction(atts);
567         result = new TableMappingImpl(colMapping, comp, tableName, conn, action,
568         generate, getBatchSize(atts), userTablesOnly);
569         context.register(result);
570         return result;
571     }
572
573     private void buildGeneratorColumnMapping(Attributes atts, boolean substitution)
574     throws SAXException {
575         TableMapping tm = peekScope().getLastInserted();
576         SchemaComponent sc = null;
577         if (tm == null) // for instance when called by an element substitution generator
578
sc = context.getCurrentNode().getSchemaComponent();
579         else
580             sc = tm.getSchemaComponent();
581         buildGeneratorColumnMapping(atts, sc, substitution);
582     }
583     
584     /**
585      * Process generator column mapping object creation.
586      */

587     private void buildGeneratorColumnMapping(Attributes atts, SchemaComponent sc, boolean substitution)
588     throws SAXException
589     {
590         Type type = null;
591         if (sc instanceof Type)
592             type = (Type)sc;
593         else // declaration
594
type = ((Declaration)sc).getType();
595         
596         TableMappingImpl tableMapping = getCurrentTableMapping();
597         String JavaDoc columnName = checkColumnName(atts.getValue("", COLUMN_ATTR), tableMapping);
598         Generator generator = null;
599         String JavaDoc ref = atts.getValue("", REF_ATTR);
600         String JavaDoc source = atts.getValue("", VAR_ATTR);
601         String JavaDoc genClass = atts.getValue("", USER_GENERATOR_ATTR);
602         if (genClass == null)
603             genClass = atts.getValue("", METHOD_ATTR); // 4 compatibility reasons
604

605         // NIY String XpathRef = atts.getValue("", XPATH_ATTR);
606

607         int defaultRole = 0;
608         if (ref != null)
609         {
610             if (source != null || genClass != null)
611             throw new SAXParseException("Can have only one of " + REF_ATTR + ", "
612                                     + VAR_ATTR + " and " + USER_GENERATOR_ATTR
613                                     + " attributes in generator declaration ("
614                                     + tableMapping.getTableName() + "." + columnName + ").",
615                                     getDocumentLocator());
616             peekScope().addPendingRef(columnName, ref, sc); // processed when getting out of the surrounding element
617
defaultRole = 0;
618         }
619         else if (source != null)
620         {
621             if (genClass != null)
622             throw new SAXParseException("Can have only one of "
623                                     + VAR_ATTR + " and " + USER_GENERATOR_ATTR
624                                     + " attributes in generator declaration ("
625                                     + tableMapping.getTableName() + "." + columnName + ").",
626                                     getDocumentLocator());
627             generator = getSystemVariableGenerator(source, type);
628             defaultRole = KEY_ROLE;
629         }
630         else if (genClass != null)
631         {
632             generator = getUserGenerator(genClass, tableMapping.getTableName(), columnName);
633             defaultRole = KEY_ROLE;
634         }
635         else
636             throw new SAXParseException("One of " + REF_ATTR + ", " + VAR_ATTR + " and " + USER_GENERATOR_ATTR
637                                     + " attributes must be specified in column mapping declaration ("
638                                     + tableMapping.getTableName() + "." + columnName + ").",
639                                     getDocumentLocator());
640         int role = getRole(atts, defaultRole);
641         // If the XML node is an attribute or a simple content element, the generator specified
642
//
643
if (substitution || generator instanceof ValueGenerator){
644             if (type instanceof SimpleType || (type instanceof ComplexType
645                 && ((ComplexType) type).getContentType() == SchemaConstants.TEXT_ONLY))
646                 context.register(new ColumnMappingImpl(tableMapping, sc, 1,
647                         columnName, getRole(atts, SELECT_ROLE), generator,
648                         messageHandler));
649             else
650                 throw new SAXParseException(
651                         "A substitution generator cannot be defined on a complex content element.",
652                         getDocumentLocator());
653         }
654         else
655             new ColumnMappingImpl(tableMapping, null, 1, columnName, role, generator, messageHandler);
656     }
657
658     
659     /**
660      * This method browse element hierarchy in schema to determine the occurence
661      * bounds within a given ancestor.
662      *
663      * @param elem
664      * element which occurence bounds are to be calculated
665      * @param ancestor
666      * scope where occurence is searched
667      * @param occurrences
668      * an int[2] array for collecting result. {min_occurs,
669      * max_occurs}
670      * @return the child element declaration of the ancestor.
671      */

672     private ElementDeclaration computeHierarchyInfo(SchemaComponent ancestor,int[] occurrences)
673     {
674         ElementDeclaration child = null;
675         SchemaComponent parent, current = null;
676         ComplexType type;
677         int[] occurrenceCount;
678         long mult;
679         Iterator it = context.iterator();
680         if (it.hasNext()) // if we're processing an attribute elem is null and occurences is filled with atttribute occurence
681
current = (ElementDeclaration)it.next();
682         while (it.hasNext() && current != ancestor)
683         {
684             parent = (SchemaComponent)it.next();
685             if (parent instanceof Declaration)
686                 type = (ComplexType)((Declaration)parent).getType();
687             else
688                 type = (ComplexType)parent;
689             
690             occurrenceCount = type.getDeclarationOccurrence
691                                 (
692                                 current.getNamespace(),
693                                 current.getName()
694                                 );
695             for (int i = 0; i <= 1; i++)
696             {
697                 mult = (long)occurrences[i] * (long)occurrenceCount[i];
698                 occurrences[i] = (mult <= Integer.MAX_VALUE ? (int)mult : Integer.MAX_VALUE);
699           &