View Javadoc
1   /**
2    * Redistribution and use of this software and associated documentation ("Software"), with or
3    * without modification, are permitted provided that the following conditions are met:
4    *
5    * 1. Redistributions of source code must retain copyright statements and notices. Redistributions
6    * must also contain a copy of this document.
7    *
8    * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
9    * conditions and the following disclaimer in the documentation and/or other materials provided with
10   * the distribution.
11   *
12   * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
13   * without prior written permission of Intalio, Inc. For written permission, please contact
14   * info@exolab.org.
15   *
16   * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
17   * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
18   * Intalio, Inc.
19   *
20   * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
21   *
22   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
23   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
25   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29   * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   * Copyright 2004 (C) Intalio Inc. All Rights Reserved.
32   *
33   * $Id$
34   */
35  package org.exolab.castor.xml.schema;
36  
37  import java.util.Collection;
38  import java.util.Collections;
39  import java.util.Hashtable;
40  import java.util.Map;
41  
42  import org.exolab.castor.xml.ValidationException;
43  
44  /**
45   * <p>
46   * This class is a wrapper used to save meta information concerning redefined structures from an XML
47   * schema.
48   * </p>
49   * 
50   * <p>
51   * This wrapper is identified by:
52   * <ul>
53   * <li>a reference to the schema redefined</li>
54   * <li>the schema location of the redefined schema</li>
55   * <li>A vector containing the names of the structures redefined</li>
56   * </ul>
57   * 
58   * @author <a href="mailto:blandin@intalio.com">Arnaud Blandin</a>
59   * @version $Revision$ $Date: 2006-04-13 06:47:36 -0600 (Thu, 13 Apr 2006) $
60   **/
61  public class RedefineSchema extends Annotated {
62    /** SerialVersionUID */
63    private static final long serialVersionUID = -7095458840388436859L;
64  
65    /**
66     * The original schema that is imported in the parent schema
67     */
68    private Schema _originalSchema;
69  
70    /**
71     * The parent schema in which this redefined XML Schema is used.
72     */
73    private Schema _parentSchema;
74  
75    /**
76     * The schema location of the redefined schema
77     */
78    private String _schemaLocation = null;
79  
80    /**
81     * A vector with the names of the redefined complexTypes
82     */
83    private Map<String, ComplexType> _complexTypes;
84  
85    /**
86     * A vector with the names of the redefined simpleTypes
87     */
88    private Map<String, SimpleType> _simpleTypes;
89  
90    /**
91     * A vector with the names of the redefined groups
92     */
93    private Map<String, ModelGroup> _groups;
94  
95    /**
96     * A vector with the names of the redefined attributeGroups
97     */
98    private Map<String, AttributeGroup> _attributeGroups;
99  
100   /**
101    * Default constructor to create a RedefineSchema that contains only Annotations
102    * 
103    */
104   public RedefineSchema(Schema parentSchema) {
105     super();
106     _parentSchema = parentSchema;
107     _schemaLocation = "";
108   }
109 
110   /**
111    * Constructs a new RedefineSchema structure
112    */
113   public RedefineSchema(Schema parentSchema, Schema originalSchema) {
114     super();
115     _schemaLocation = originalSchema.getSchemaLocation();
116     _parentSchema = parentSchema;
117     _originalSchema = originalSchema;
118     _complexTypes = new Hashtable<String, ComplexType>();
119     _simpleTypes = new Hashtable<String, SimpleType>();
120     _attributeGroups = new Hashtable<String, AttributeGroup>();
121     _groups = new Hashtable<String, ModelGroup>();
122   }
123 
124   /**
125    * Adds the given complexType in the list of redefined complexTypes.
126    * 
127    * @param complexType the ComplexType to add.
128    */
129   public void addComplexType(ComplexType complexType) throws SchemaException {
130     if (_schemaLocation.length() == 0)
131       throw new IllegalStateException(
132           "A RedefineSchema with no schemaLocation must contain only annotations");
133     String name = complexType.getName();
134 
135     if (name == null) {
136       String err = "a global ComplexType must contain a name.";
137       throw new SchemaException(err);
138     }
139 
140     if (complexType.getSchema() != _parentSchema) {
141       String err = "invalid attempt to add an ComplexType which ";
142       err += "belongs to a different Schema; type name: " + name;
143       throw new SchemaException(err);
144     }
145 
146     if (getComplexType(name) != null) {
147       String err = "In the RedefineSchema:" + _schemaLocation
148           + "a ComplexType already exists with the given name: ";
149       throw new SchemaException(err + name);
150     }
151 
152     // --forces the redefine character
153     complexType.setRedefined();
154 
155     _complexTypes.put(name, complexType);
156     complexType.setParent(_parentSchema);
157   }
158 
159   /**
160    * Enumerates the complexType names.
161    * 
162    * @return an enumeration of the names of the redefined ComplexTypes
163    */
164   public Collection<ComplexType> enumerateComplexTypes() {
165     if (_schemaLocation.length() == 0) {
166       return Collections.emptyList();
167     }
168     return _complexTypes.values();
169   }
170 
171   /**
172    * Returns the ComplexType corresponding to the given name.
173    * 
174    * @param name the name of the ComplexType to look for.
175    * @return the ComplexType corresponding to the gven name.
176    */
177   public ComplexType getComplexType(String name) {
178     if (_schemaLocation.length() == 0) {
179       return null;
180     }
181 
182     return _complexTypes.get(name);
183   }
184 
185   /**
186    * Returns true if this redefinition contains a redefinition for a complexType with the given
187    * name.
188    * 
189    * @param name the canonical name of the complexType.
190    */
191   public boolean hasComplexTypeRedefinition(String name) {
192     if (_schemaLocation.length() == 0)
193       return false;
194 
195     return (_complexTypes.containsKey(name));
196   }
197 
198   /**
199    * Removes the complexType with the given name from the redefine structure.
200    * 
201    * @param complexType The complexType to be removed from this Redefined Structure.
202    */
203   public boolean removeComplexType(ComplexType complexType) {
204     if (_schemaLocation.length() == 0)
205       return false;
206 
207     boolean result = false;
208     if (_complexTypes.containsValue(complexType)) {
209       _complexTypes.remove(complexType);
210       result = true;
211     }
212     return result;
213   }
214 
215   /**
216    * Adds a simpleType in the list of redefined simpleTypes.
217    * 
218    * @param simpleType the SimpleType to add.
219    */
220   public void addSimpleType(SimpleType simpleType) throws SchemaException {
221 
222     String name = simpleType.getName();
223     if (name == null)
224       throw new IllegalArgumentException("A redefined simpleType must have a name");
225     if (_schemaLocation.length() == 0)
226       throw new IllegalStateException(
227           "A RedefineSchema with no schemaLocation must contain only annotations");
228 
229     if (simpleType.getSchema() != _parentSchema) {
230       String err = "invalid attempt to add a SimpleType which ";
231       err += "belongs to a different Schema; type name: " + name;
232       throw new SchemaException(err);
233     }
234 
235     if (getSimpleType(name) != null) {
236       String err = "In the RedefineSchema:" + _schemaLocation
237           + "a SimpleType already exists with the given name: ";
238       throw new SchemaException(err + name);
239     }
240     // --forces the redefine character
241     simpleType.setRedefined();
242 
243     simpleType.setParent(this);
244     _simpleTypes.put(name, simpleType);
245   }
246 
247   /**
248    * Enumerates the simpleType names.
249    * 
250    * @return an enumeration of the names of the redefined SimpleTypes.
251    */
252   public Collection<SimpleType> enumerateSimpleTypes() {
253     if (_schemaLocation.length() == 0) {
254       return Collections.emptyList();
255     }
256 
257     return _simpleTypes.values();
258   }
259 
260   /**
261    * Returns the SimpleType corresponding to the given name.
262    * 
263    * @param name the name of the SimpleType to look for.
264    * @return the SimpleType corresponding to the gven name.
265    */
266   public SimpleType getSimpleType(String name) {
267     if (_schemaLocation.length() == 0) {
268       return null;
269     }
270 
271     return _simpleTypes.get(name);
272   }
273 
274   /**
275    * Returns true if this redefinition contains a redefinition for a simpleType with the given name.
276    * 
277    * @param name the canonical name of the simpleType.
278    */
279   public boolean hasSimpleTypeRedefinition(String name) {
280     if (_schemaLocation.length() == 0) {
281       return false;
282     }
283 
284     return (_simpleTypes.containsKey(name));
285   }
286 
287   /**
288    * Removes the given simpleType from the redefine structure.
289    * 
290    * @param simpleType the simpleType to be removed from this Redefined Structure.
291    */
292   public boolean removeSimpleType(SimpleType simpleType) {
293     if (_schemaLocation.length() == 0)
294       return false;
295 
296     boolean result = false;
297     if (_simpleTypes.containsValue(simpleType)) {
298       _simpleTypes.remove(simpleType);
299       result = true;
300     }
301     return result;
302   }
303 
304   /**
305    * Adds a group name in the list of redefined groups.
306    */
307   public void addGroup(ModelGroup group) throws SchemaException {
308     if (_schemaLocation.length() == 0) {
309       throw new IllegalStateException(
310           "A RedefineSchema with no schemaLocation must contain only annotations");
311     }
312 
313     String name = group.getName();
314 
315     if (name == null) {
316       String err = "a group declaration must contain a name.";
317       throw new SchemaException(err);
318     }
319 
320     if (getModelGroup(name) != null) {
321       String err = "In the RedefineSchema:" + _schemaLocation
322           + " a group declaration already exists with the given name: ";
323       throw new SchemaException(err + name);
324     }
325     // --forces the redefine character
326     group.setRedefined();
327     group.setParent(_parentSchema);
328 
329     _groups.put(name, group);
330   }
331 
332   /**
333    * Returns the Model Group of the given name that is contained in this RedefineSchema.
334    * 
335    * @param name the name of the ModelGroup to retrieve.
336    * @return the ModelGroup of the given name contained in this RedefineSchema.
337    */
338   public ModelGroup getModelGroup(String name) {
339     if (_schemaLocation.length() == 0) {
340       return null;
341     }
342 
343     return _groups.get(name);
344   }
345 
346   /**
347    * Enumerates the group names.
348    * 
349    * @return an enumeration of the names of the redefined groups.
350    */
351   public Collection<ModelGroup> enumerateGroups() {
352     if (_schemaLocation.length() == 0) {
353       return Collections.emptyList();
354     }
355 
356     return _groups.values();
357   }
358 
359   /**
360    * Returns true if this redefinition contains a redefinition for a group with the given name.
361    * 
362    * @param name the canonical name of the complexType.
363    */
364   public boolean hasGroupRedefinition(String name) {
365     if (_schemaLocation.length() == 0)
366       return false;
367 
368     return (_groups.containsKey(name));
369   }
370 
371   /**
372    * Removes the given ModelGroup from the redefine structure.
373    * 
374    * @param group the ModelGroup to be removed from this Redefined Structure.
375    */
376   public boolean removeGroup(ModelGroup group) {
377     if (_schemaLocation.length() == 0)
378       return false;
379 
380     boolean result = false;
381     if (_groups.containsValue(group)) {
382       _groups.remove(group);
383       result = true;
384     }
385     return result;
386   }
387 
388   /**
389    * Adds a AttributeGroup name in the list of redefined attributeGroups.
390    */
391   public void addAttributeGroup(AttributeGroupDecl attrGroup) throws SchemaException {
392     if (_schemaLocation.length() == 0)
393       throw new IllegalStateException(
394           "A RedefineSchema with no schemaLocation must contain only annotations");
395 
396     if (attrGroup == null)
397       return;
398 
399     String name = attrGroup.getName();
400 
401     // -- handle namespace prefix, if necessary
402     int idx = name.indexOf(':');
403     if (idx >= 0) {
404       String nsPrefix = name.substring(0, idx);
405       name = name.substring(idx + 1);
406       String ns = _parentSchema.getNamespace(nsPrefix);
407       if (ns == null) {
408         String err = "addAttributeGroup: ";
409         err += "Namespace prefix not recognized '" + nsPrefix + "'";
410         throw new IllegalArgumentException(err);
411       }
412       if (!ns.equals(_parentSchema.getTargetNamespace())) {
413         String err = "AttributeGroup has different namespace " + "than this Schema definition.";
414         throw new IllegalArgumentException(err);
415       }
416     }
417 
418     if (attrGroup.getSchema() != _parentSchema) {
419       String err = "invalid attempt to add an AttributeGroup which ";
420       err += "belongs to a different Schema; " + name;
421       throw new SchemaException(err);
422     }
423 
424     attrGroup.setRedefined();
425 
426     _attributeGroups.put(name, attrGroup);
427   }
428 
429   /**
430    * Returns the AttributeGroup corresponding to the given canonical name (unqualified name).
431    * 
432    * @return the AttributeGroup corresponding to the given canonical name (unqualified name).
433    */
434   public AttributeGroupDecl getAttributeGroup(String name) {
435     if (_schemaLocation.length() == 0)
436       return null;
437 
438     return (AttributeGroupDecl) _attributeGroups.get(name);
439   }
440 
441   /**
442    * Enumerates the attributeGroup names.
443    * 
444    * @return an enumeration of the names of the redefined AttributeGroups.
445    */
446   public Collection<AttributeGroup> enumerateAttributeGroups() {
447     if (_schemaLocation.length() == 0) {
448       return Collections.emptyList();
449     }
450 
451     return _attributeGroups.values();
452   }
453 
454   /**
455    * Returns true if this redefinition contains a redefinition for an AttributeGroup with the given
456    * name.
457    * 
458    * @param name the canonical name of the complexType.
459    */
460   public boolean hasAttributeGroupRedefinition(String name) {
461     if (_schemaLocation.length() == 0)
462       return false;
463 
464     return (_attributeGroups.containsKey(name));
465   }
466 
467   /**
468    * Removes the attributeGroup with the given name from the redefine structure.
469    * 
470    * @param attrGroup the attributeGroup to be removed from this Redefined Structure.
471    */
472   public boolean removeAttributeGroup(AttributeGroupDecl attrGroup) {
473     if (_schemaLocation.length() == 0)
474       return false;
475 
476     boolean result = false;
477     if (_attributeGroups.containsValue(attrGroup)) {
478       _attributeGroups.remove(attrGroup);
479       result = true;
480     }
481     return result;
482   }
483 
484   /**
485    * Returns true if at least one structure other than an annotation is present.
486    * 
487    * @return true if at least one structure other than an annotation is present.
488    */
489   public boolean hasRedefinition() {
490     if (_schemaLocation.length() == 0)
491       return false;
492 
493     return (!_complexTypes.isEmpty()) || (!_simpleTypes.isEmpty()) || (!_groups.isEmpty())
494         || (!_attributeGroups.isEmpty());
495   }
496 
497   /**
498    * Returns the URI of the imported schema.
499    * 
500    * @return the URI of the imported schema.
501    */
502   public String getSchemaLocation() {
503     return _schemaLocation;
504   }
505 
506   /**
507    * Returns the schema imported used for the redefinitions.
508    * 
509    * @return the original schema imported.
510    */
511   public Schema getOriginalSchema() {
512     return _originalSchema;
513   }
514 
515   /**
516    * Returns the parent schema in which this RedefineSchema is used.
517    * 
518    * @return the parent schema in which this Redefined Schema is used.
519    */
520   public Schema getParentSchema() {
521     return _parentSchema;
522   }
523 
524   /**
525    * Returns the type of this Redefine Structure
526    * 
527    * @return the type of this Redefin Structure
528    **/
529   public short getStructureType() {
530     return Structure.REDEFINE;
531   } // -- getStructureType
532 
533 
534   public void validate() throws ValidationException {
535     // -- no validation performed on the structure since
536     // -- it is simply a place holder for names and not for real structures.
537   }
538 
539 }