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