1 /* Copyright 2004 The Apache Software Foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package org.apache.xmlbeans.impl.schema;
17
18 import org.apache.xmlbeans.Filer;
19 import org.apache.xmlbeans.QNameSet;
20 import org.apache.xmlbeans.SchemaAnnotation;
21 import org.apache.xmlbeans.SchemaAttributeGroup;
22 import org.apache.xmlbeans.SchemaAttributeModel;
23 import org.apache.xmlbeans.SchemaComponent;
24 import org.apache.xmlbeans.SchemaField;
25 import org.apache.xmlbeans.SchemaGlobalAttribute;
26 import org.apache.xmlbeans.SchemaGlobalElement;
27 import org.apache.xmlbeans.SchemaIdentityConstraint;
28 import org.apache.xmlbeans.SchemaLocalAttribute;
29 import org.apache.xmlbeans.SchemaLocalElement;
30 import org.apache.xmlbeans.SchemaModelGroup;
31 import org.apache.xmlbeans.SchemaParticle;
32 import org.apache.xmlbeans.SchemaProperty;
33 import org.apache.xmlbeans.SchemaStringEnumEntry;
34 import org.apache.xmlbeans.SchemaType;
35 import org.apache.xmlbeans.SchemaTypeLoader;
36 import org.apache.xmlbeans.SchemaTypeLoaderException;
37 import org.apache.xmlbeans.SchemaTypeSystem;
38 import org.apache.xmlbeans.SimpleValue;
39 import org.apache.xmlbeans.SystemProperties;
40 import org.apache.xmlbeans.XmlAnySimpleType;
41 import org.apache.xmlbeans.XmlObject;
42 import org.apache.xmlbeans.XmlOptions;
43 import org.apache.xmlbeans.ResourceLoader;
44 import org.apache.xmlbeans.impl.common.NameUtil;
45 import org.apache.xmlbeans.impl.common.QNameHelper;
46 import org.apache.xmlbeans.impl.common.XBeanDebug;
47 import org.apache.xmlbeans.impl.util.FilerImpl;
48 import org.apache.xmlbeans.impl.util.HexBin;
49 import org.apache.xmlbeans.impl.values.XmlObjectBase;
50 import org.apache.xmlbeans.impl.xb.xsdschema.AttributeGroupDocument;
51 import org.apache.xmlbeans.impl.xb.xsdschema.GroupDocument;
52 import org.apache.xmlbeans.soap.SOAPArrayType;
53 import org.apache.xmlbeans.soap.SchemaWSDLArrayType;
54 import repackage.Repackager;
55
56 import javax.xml.namespace.QName;
57 import java.io.ByteArrayOutputStream;
58 import java.io.DataInputStream;
59 import java.io.DataOutputStream;
60 import java.io.File;
61 import java.io.IOException;
62 import java.io.InputStream;
63 import java.io.OutputStream;
64 import java.math.BigInteger;
65 import java.util.ArrayList;
66 import java.util.Arrays;
67 import java.util.Collections;
68 import java.util.HashMap;
69 import java.util.HashSet;
70 import java.util.Iterator;
71 import java.util.LinkedHashMap;
72 import java.util.LinkedHashSet;
73 import java.util.List;
74 import java.util.Map;
75 import java.util.Random;
76 import java.util.Set;
77 import java.util.zip.ZipEntry;
78 import java.util.zip.ZipFile;
79
80 public class SchemaTypeSystemImpl extends SchemaTypeLoaderBase implements SchemaTypeSystem
81 {
82 public static final int DATA_BABE = 0xDA7ABABE;
83 public static final int MAJOR_VERSION = 2; // must match == to be compatible
84 public static final int MINOR_VERSION = 24; // must be <= to be compatible
85 public static final int RELEASE_NUMBER = 0; // should be compatible even if < or >
86
87 public static final int FILETYPE_SCHEMAINDEX = 1;
88 public static final int FILETYPE_SCHEMATYPE = 2;
89 public static final int FILETYPE_SCHEMAELEMENT = 3;
90 public static final int FILETYPE_SCHEMAATTRIBUTE = 4;
91 public static final int FILETYPE_SCHEMAPOINTER = 5;
92 public static final int FILETYPE_SCHEMAMODELGROUP = 6;
93 public static final int FILETYPE_SCHEMAATTRIBUTEGROUP = 7;
94 public static final int FILETYPE_SCHEMAIDENTITYCONSTRAINT = 8;
95
96 public static final int FLAG_PART_SKIPPABLE = 1;
97 public static final int FLAG_PART_FIXED = 4;
98 public static final int FLAG_PART_NILLABLE = 8;
99 public static final int FLAG_PART_BLOCKEXT = 16;
100 public static final int FLAG_PART_BLOCKREST = 32;
101 public static final int FLAG_PART_BLOCKSUBST = 64;
102 public static final int FLAG_PART_ABSTRACT = 128;
103 public static final int FLAG_PART_FINALEXT = 256;
104 public static final int FLAG_PART_FINALREST = 512;
105
106 public static final int FLAG_PROP_ISATTR = 1;
107 public static final int FLAG_PROP_JAVASINGLETON = 2;
108 public static final int FLAG_PROP_JAVAOPTIONAL = 4;
109 public static final int FLAG_PROP_JAVAARRAY = 8;
110
111 public static final int FIELD_NONE = 0;
112 public static final int FIELD_GLOBAL = 1;
113 public static final int FIELD_LOCALATTR = 2;
114 public static final int FIELD_LOCALELT = 3;
115
116 // type flags
117 static final int FLAG_SIMPLE_TYPE = 0x1;
118 static final int FLAG_DOCUMENT_TYPE = 0x2;
119 static final int FLAG_ORDERED = 0x4;
120 static final int FLAG_BOUNDED = 0x8;
121 static final int FLAG_FINITE = 0x10;
122 static final int FLAG_NUMERIC = 0x20;
123 static final int FLAG_STRINGENUM = 0x40;
124 static final int FLAG_UNION_OF_LISTS = 0x80;
125 static final int FLAG_HAS_PATTERN = 0x100;
126 static final int FLAG_ORDER_SENSITIVE = 0x200;
127 static final int FLAG_TOTAL_ORDER = 0x400;
128 static final int FLAG_COMPILED = 0x800;
129 static final int FLAG_BLOCK_EXT = 0x1000;
130 static final int FLAG_BLOCK_REST = 0x2000;
131 static final int FLAG_FINAL_EXT = 0x4000;
132 static final int FLAG_FINAL_REST = 0x8000;
133 static final int FLAG_FINAL_UNION = 0x10000;
134 static final int FLAG_FINAL_LIST = 0x20000;
135 static final int FLAG_ABSTRACT = 0x40000;
136 static final int FLAG_ATTRIBUTE_TYPE = 0x80000;
137
138 /**
139 * This is to support the feature of a separate/private XMLBeans
140 * distribution that will not colide with the public org apache
141 * xmlbeans one.
142 * METADATA_PACKAGE_GEN will be "" for the original and something like
143 * com_mycompany_private_xmlbeans for a private distribution of XMLBeans.
144 *
145 * There are two properties:
146 * METADATA_PACKAGE_GEN - used for generating metadata
147 * and METADATA_PACKAGE_LOAD - used for loading the metadata.
148 * Most of the time they have the same value, with one exception, during the
149 * repackage process scomp needs to load from old package and generate into
150 * a new package.
151 */
152 public static String METADATA_PACKAGE_GEN;
153 static
154 {
155 // fix for maven classloader
156 Package stsPackage = SchemaTypeSystem.class.getPackage();
157 String stsPackageName = (stsPackage==null) ?
158 SchemaTypeSystem.class.getName().substring(0, SchemaTypeSystem.class.getName().lastIndexOf(".")) :
159 stsPackage.getName();
160
161 METADATA_PACKAGE_GEN = stsPackageName.replaceAll("\\.", "_");
162 }
163
164 private static String nameToPathString(String nameForSystem)
165 {
166 nameForSystem = nameForSystem.replace('.', '/');
167
168 if (!nameForSystem.endsWith("/") && nameForSystem.length() > 0)
169 nameForSystem = nameForSystem + "/";
170
171 return nameForSystem;
172 }
173
174 public SchemaTypeSystemImpl(Class indexclass)
175 {
176 String fullname = indexclass.getName();
177 _name = fullname.substring(0, fullname.lastIndexOf('.'));
178 XBeanDebug.trace(XBeanDebug.TRACE_SCHEMA_LOADING, "Loading type system " + _name, 1);
179 _basePackage = nameToPathString(_name);
180 _classloader = indexclass.getClassLoader();
181 _linker = SchemaTypeLoaderImpl.build(null, null, _classloader);
182 _resourceLoader = new ClassLoaderResourceLoader(_classloader);
183 try
184 {
185 initFromHeader();
186 }
187 catch (RuntimeException e)
188 {
189 XBeanDebug.logException(e);
190 throw e;
191 }
192 catch (Error e)
193 {
194 XBeanDebug.logException(e);
195 throw e;
196 }
197 XBeanDebug.trace(XBeanDebug.TRACE_SCHEMA_LOADING, "Finished loading type system " + _name, -1);
198 }
199
200 public static boolean fileContainsTypeSystem(File file, String name)
201 {
202 String indexname = nameToPathString(name) + "index.xsb";
203
204 if (file.isDirectory())
205 {
206 return (new File(file, indexname)).isFile();
207 }
208 else
209 {
210 ZipFile zipfile = null;
211 try
212 {
213 zipfile = new ZipFile(file);
214 ZipEntry entry = zipfile.getEntry(indexname);
215 return (entry != null && !entry.isDirectory());
216 }
217 catch (IOException e)
218 {
219 XBeanDebug.log("Problem loading SchemaTypeSystem, zipfilename " + file);
220 XBeanDebug.logException(e);
221 throw new SchemaTypeLoaderException(e.getMessage(), name, "index", SchemaTypeLoaderException.IO_EXCEPTION);
222 }
223 finally
224 {
225 if (zipfile != null)
226 try { zipfile.close(); } catch (IOException e) {}
227 }
228 }
229 }
230
231 public static SchemaTypeSystemImpl forName(String name, ClassLoader loader)
232 {
233 try
234 {
235 Class c = Class.forName(name + "." + SchemaTypeCodePrinter.INDEX_CLASSNAME, true, loader);
236 return (SchemaTypeSystemImpl)c.getField("typeSystem").get(null);
237 }
238 catch (Exception e)
239 {
240 return null;
241 }
242 }
243
244 public SchemaTypeSystemImpl(ResourceLoader resourceLoader, String name, SchemaTypeLoader linker)
245 {
246 _name = name;
247 _basePackage = nameToPathString(_name);
248 _linker = linker;
249 _resourceLoader = resourceLoader;
250 try
251 {
252 initFromHeader();
253 }
254 catch (RuntimeException e)
255 {
256 XBeanDebug.logException(e);
257 throw e;
258 }
259 catch (Error e)
260 {
261 XBeanDebug.logException(e);
262 throw e;
263 }
264 }
265
266 private void initFromHeader()
267 {
268 XBeanDebug.trace(XBeanDebug.TRACE_SCHEMA_LOADING, "Reading unresolved handles for type system " + _name, 0);
269 XsbReader reader = null;
270 try
271 {
272 // Read the index file, which starts with a header.
273 reader = new XsbReader("index", FILETYPE_SCHEMAINDEX);
274
275 // has a handle pool (count, handle/type, handle/type...)
276 _localHandles = new HandlePool();
277 reader.readHandlePool(_localHandles);
278
279 // then a qname map of global elements (count, qname/handle, qname/handle...)
280 _globalElements = reader.readQNameRefMap();
281
282 // qname map of global attributes
283 _globalAttributes = reader.readQNameRefMap();
284
285 // qname map of model groups
286 _modelGroups = reader.readQNameRefMap();
287
288 // qname map of attribute groups
289 _attributeGroups = reader.readQNameRefMap();
290
291 _identityConstraints = reader.readQNameRefMap();
292
293 // qname map of global types
294 _globalTypes = reader.readQNameRefMap();
295
296 // qname map of document types, by the qname of the contained element
297 _documentTypes = reader.readQNameRefMap();
298
299 // qname mape of attribute types, by the qname of the contained attribute
300 _attributeTypes = reader.readQNameRefMap();
301
302 // string map of all types, by fully qualified classname
303 _typeRefsByClassname = reader.readClassnameRefMap();
304
305 _namespaces = reader.readNamespaces();
306
307 // support for redefine, at the end of the file
308 List typeNames = new ArrayList();
309 List modelGroupNames = new ArrayList();
310 List attributeGroupNames = new ArrayList();
311 if (reader.atLeast(2, 15, 0))
312 {
313 _redefinedGlobalTypes = reader.readQNameRefMapAsList(typeNames);
314 _redefinedModelGroups = reader.readQNameRefMapAsList(modelGroupNames);
315 _redefinedAttributeGroups = reader.readQNameRefMapAsList(attributeGroupNames);
316 }
317 if (reader.atLeast(2, 19, 0))
318 {
319 _annotations = reader.readAnnotations();
320 }
321
322 buildContainers(typeNames, modelGroupNames, attributeGroupNames);
323 }
324 finally
325 {
326 if (reader != null)
327 reader.readEnd();
328 }
329 }
330
331 void saveIndex()
332 {
333 String handle = "index";
334 XsbReader saver = new XsbReader(handle);
335 saver.writeIndexData();
336 saver.writeRealHeader(handle, FILETYPE_SCHEMAINDEX);
337 saver.writeIndexData();
338 saver.writeEnd();
339 }
340
341 void savePointers()
342 {
343 savePointersForComponents(globalElements(), "schema" + METADATA_PACKAGE_GEN + "/element/");
344 savePointersForComponents(globalAttributes(), "schema" + METADATA_PACKAGE_GEN + "/attribute/");
345 savePointersForComponents(modelGroups(), "schema" + METADATA_PACKAGE_GEN + "/modelgroup/");
346 savePointersForComponents(attributeGroups(), "schema" + METADATA_PACKAGE_GEN + "/attributegroup/");
347 savePointersForComponents(globalTypes(), "schema" + METADATA_PACKAGE_GEN + "/type/");
348 savePointersForComponents(identityConstraints(), "schema" + METADATA_PACKAGE_GEN + "/identityconstraint/");
349 savePointersForNamespaces(_namespaces, "schema" + METADATA_PACKAGE_GEN + "/namespace/");
350 savePointersForClassnames(_typeRefsByClassname.keySet(), "schema" + METADATA_PACKAGE_GEN + "/javaname/");
351 savePointersForComponents(redefinedModelGroups(), "schema" + METADATA_PACKAGE_GEN + "/redefinedmodelgroup/");
352 savePointersForComponents(redefinedAttributeGroups(), "schema" + METADATA_PACKAGE_GEN + "/redefinedattributegroup/");
353 savePointersForComponents(redefinedGlobalTypes(), "schema" + METADATA_PACKAGE_GEN + "/redefinedtype/");
354 }
355
356 void savePointersForComponents(SchemaComponent[] components, String dir)
357 {
358 for (int i = 0; i < components.length; i++)
359 {
360 savePointerFile(dir + QNameHelper.hexsafedir(components[i].getName()), _name);
361 }
362 }
363
364 void savePointersForClassnames(Set classnames, String dir)
365 {
366 for (Iterator i = classnames.iterator(); i.hasNext(); )
367 {
368 String classname = (String)i.next();
369 savePointerFile(dir + classname.replace('.', '/'), _name);
370 }
371 }
372
373 void savePointersForNamespaces(Set namespaces, String dir)
374 {
375 for (Iterator i = namespaces.iterator(); i.hasNext(); )
376 {
377 String ns = (String)i.next();
378 savePointerFile(dir + QNameHelper.hexsafedir(new QName(ns, "xmlns")), _name);
379 }
380 }
381
382 void savePointerFile(String filename, String name)
383 {
384 XsbReader saver = new XsbReader(filename);
385 saver.writeString(name);
386 saver.writeRealHeader(filename, FILETYPE_SCHEMAPOINTER);
387 saver.writeString(name);
388 saver.writeEnd();
389 }
390
391 /**
392 * The strategy here is to copy the compiled TypeSystemHolder.template class
393 * to a new TypeSystemHolder.class needed by the schema type system. When
394 * saving a loader, we read the TypeSystemHolder.template class file and
395 * swap out the utf8 string constants with new ones to create a new
396 * TypeSystemHolder class file. This saves us the need to rely on javac
397 * to compile a generated .java file into the class file.
398 *
399 * See the JVM spec on how to interpret the bytes of a class file.
400 */
401 void saveLoader()
402 {
403 String indexClassName = SchemaTypeCodePrinter.indexClassForSystem(this);
404 String[] replace = makeClassStrings(indexClassName);
405 assert replace.length == HOLDER_TEMPLATE_NAMES.length;
406
407 InputStream is = null;
408 OutputStream os = null;
409
410 DataInputStream in = null;
411 DataOutputStream out = null;
412
413 Repackager repackager = null;
414 if (_filer instanceof FilerImpl)
415 repackager = ((FilerImpl)_filer).getRepackager();
416
417 try
418 {
419 is = SchemaTypeSystemImpl.class.getResourceAsStream(HOLDER_TEMPLATE_CLASSFILE);
420 if (is == null)
421 throw new SchemaTypeLoaderException("couldn't find resource: " + HOLDER_TEMPLATE_CLASSFILE, _name, null, SchemaTypeLoaderException.IO_EXCEPTION);
422 in = new DataInputStream(is);
423
424 os = _filer.createBinaryFile(indexClassName.replace('.', '/') + ".class");
425 out = new DataOutputStream(os);
426
427 // java magic
428 out.writeInt(in.readInt());
429
430 // java minor and major version
431 out.writeShort(in.readUnsignedShort());
432 out.writeShort(in.readUnsignedShort());
433
434 int poolsize = in.readUnsignedShort();
435 out.writeShort(poolsize);
436
437 // the constant pool is indexed from 1 to poolsize-1
438 for (int i = 1; i < poolsize; i++)
439 {
440 int tag = in.readUnsignedByte();
441 out.writeByte(tag);
442
443 switch (tag)
444 {
445 case CONSTANT_UTF8:
446 String value = in.readUTF();
447 out.writeUTF(repackageConstant(value, replace, repackager));
448 break;
449
450 case CONSTANT_CLASS:
451 case CONSTANT_STRING:
452 out.writeShort(in.readUnsignedShort());
453 break;
454
455 case CONSTANT_NAMEANDTYPE:
456 case CONSTANT_METHOD:
457 case CONSTANT_FIELD:
458 case CONSTANT_INTERFACEMETHOD:
459 out.writeShort(in.readUnsignedShort());
460 out.writeShort(in.readUnsignedShort());
461 break;
462
463 case CONSTANT_INTEGER:
464 case CONSTANT_FLOAT:
465 out.writeInt(in.readInt());
466 break;
467
468 case CONSTANT_LONG:
469 case CONSTANT_DOUBLE:
470 out.writeInt(in.readInt());
471 out.writeInt(in.readInt());
472 break;
473
474 default:
475 throw new RuntimeException("Unexpected constant type: " + tag);
476 }
477 }
478
479 // we're done with the class' constant pool,
480 // we can just copy the rest of the bytes
481 try
482 {
483 while (true)
484 out.writeByte(in.readByte());
485 }
486 catch (java.io.EOFException e)
487 {
488 // ok
489 }
490
491 }
492 catch (IOException e)
493 {
494 // ok
495 }
496 finally
497 {
498 if (is != null) try { is.close(); } catch (Exception e) { }
499 if (os != null) try { os.close(); } catch (Exception e) { }
500 }
501 }
502
503 private static final String HOLDER_TEMPLATE_CLASS = "org.apache.xmlbeans.impl.schema.TypeSystemHolder";
504 private static final String HOLDER_TEMPLATE_CLASSFILE = "TypeSystemHolder.template";
505 private static final String[] HOLDER_TEMPLATE_NAMES = makeClassStrings(HOLDER_TEMPLATE_CLASS);
506
507 // constant pool entry types
508 private static final int CONSTANT_UTF8 = 1;
509 private static final int CONSTANT_UNICODE = 2;
510 private static final int CONSTANT_INTEGER = 3;
511 private static final int CONSTANT_FLOAT = 4;
512 private static final int CONSTANT_LONG = 5;
513 private static final int CONSTANT_DOUBLE = 6;
514 private static final int CONSTANT_CLASS = 7;
515 private static final int CONSTANT_STRING = 8;
516 private static final int CONSTANT_FIELD = 9;
517 private static final int CONSTANT_METHOD = 10;
518 private static final int CONSTANT_INTERFACEMETHOD = 11;
519 private static final int CONSTANT_NAMEANDTYPE = 12;
520
521 // MAX_UNSIGNED_SHORT
522 private static final int MAX_UNSIGNED_SHORT = Short.MAX_VALUE * 2 + 1;
523
524 private static String repackageConstant(String value, String[] replace, Repackager repackager)
525 {
526 for (int i = 0; i < HOLDER_TEMPLATE_NAMES.length; i++)
527 if (HOLDER_TEMPLATE_NAMES[i].equals(value))
528 return replace[i];
529
530 if (repackager != null)
531 return repackager.repackage(new StringBuffer(value)).toString();
532
533 return value;
534 }
535
536 /**
537 * Construct an array of Strings found in a class file for a classname.
538 * For the class name 'a.b.C' it will generate an array of:
539 * 'a.b.C', 'a/b/C', 'La/b/C;', and 'class$a$b$C'.
540 */
541 private static String[] makeClassStrings(String classname)
542 {
543 String[] result = new String[4];
544
545 result[0] = classname;
546 result[1] = classname.replace('.', '/');
547 result[2] = "L" + result[1] + ";";
548 result[3] = "class$" + classname.replace('.', '$');
549
550 return result;
551 }
552
553 /**
554 * Only used in the nonbootstrapped case.
555 */
556 private Map buildTypeRefsByClassname()
557 {
558 List allSeenTypes = new ArrayList();
559 Map result = new LinkedHashMap();
560 allSeenTypes.addAll(Arrays.asList(documentTypes()));
561 allSeenTypes.addAll(Arrays.asList(attributeTypes()));
562 allSeenTypes.addAll(Arrays.asList(globalTypes()));
563
564 // now fully javaize everything deeply.
565 for (int i = 0; i < allSeenTypes.size(); i++)
566 {
567 SchemaType gType = (SchemaType)allSeenTypes.get(i);
568 String className = gType.getFullJavaName();
569 if (className != null)
570 {
571 result.put(className.replace('$', '.'), gType.getRef());
572 }
573 allSeenTypes.addAll(Arrays.asList(gType.getAnonymousTypes()));
574 }
575 return result;
576 }
577
578 private Map buildTypeRefsByClassname(Map typesByClassname)
579 {
580 Map result = new LinkedHashMap();
581 for (Iterator i = typesByClassname.keySet().iterator(); i.hasNext(); )
582 {
583 String className = (String)i.next();
584 result.put(className, ((SchemaType)typesByClassname.get(className)).getRef());
585 }
586 return result;
587 }
588
589 private static Map buildComponentRefMap(SchemaComponent[] components)
590 {
591 Map result = new LinkedHashMap();
592 for (int i = 0; i < components.length; i++)
593 result.put(components[i].getName(), components[i].getComponentRef());
594 return result;
595 }
596
597 private static List buildComponentRefList(SchemaComponent[] components)
598 {
599 List result = new ArrayList();
600 for (int i = 0; i < components.length; i++)
601 result.add(components[i].getComponentRef());
602 return result;
603 }
604
605 private static Map buildDocumentMap(SchemaType[] types)
606 {
607 Map result = new LinkedHashMap();
608 for (int i = 0; i < types.length; i++)
609 result.put(types[i].getDocumentElementName(), types[i].getRef());
610 return result;
611 }
612
613 private static Map buildAttributeTypeMap(SchemaType[] types)
614 {
615 Map result = new LinkedHashMap();
616 for (int i = 0; i < types.length; i++)
617 result.put(types[i].getAttributeTypeAttributeName(), types[i].getRef());
618 return result;
619 }
620
621 // Container operation
622 private SchemaContainer getContainer(String namespace)
623 {
624 return (SchemaContainer) _containers.get(namespace);
625 }
626
627 private void addContainer(String namespace)
628 {
629 SchemaContainer c = new SchemaContainer(namespace);
630 c.setTypeSystem(this);
631 _containers.put(namespace, c);
632 }
633
634 private SchemaContainer getContainerNonNull(String namespace)
635 {
636 SchemaContainer result = getContainer(namespace);
637 if (result == null)
638 {
639 addContainer(namespace);
640 result = getContainer(namespace);
641 }
642 return result;
643 }
644
645 // Only called during init
646 private void buildContainers(List redefTypeNames, List redefModelGroupNames, List redefAttributeGroupNames)
647 {
648 // This method walks the reference maps and copies said references
649 // into the appropriate container
650 for (Iterator it = _globalElements.entrySet().iterator(); it.hasNext(); )
651 {
652 Map.Entry entry = (Map.Entry) it.next();
653 String ns = ((QName) entry.getKey()).getNamespaceURI();
654 getContainerNonNull(ns).addGlobalElement((SchemaGlobalElement.Ref) entry.getValue());
655 }
656 for (Iterator it = _globalAttributes.entrySet().iterator(); it.hasNext(); )
657 {
658 Map.Entry entry = (Map.Entry) it.next();
659 String ns = ((QName) entry.getKey()).getNamespaceURI();
660 getContainerNonNull(ns).addGlobalAttribute((SchemaGlobalAttribute.Ref) entry.getValue());
661 }
662 for (Iterator it = _modelGroups.entrySet().iterator(); it.hasNext(); )
663 {
664 Map.Entry entry = (Map.Entry) it.next();
665 String ns = ((QName) entry.getKey()).getNamespaceURI();
666 getContainerNonNull(ns).addModelGroup((SchemaModelGroup.Ref) entry.getValue());
667 }
668 for (Iterator it = _attributeGroups.entrySet().iterator(); it.hasNext(); )
669 {
670 Map.Entry entry = (Map.Entry) it.next();
671 String ns = ((QName) entry.getKey()).getNamespaceURI();
672 getContainerNonNull(ns).addAttributeGroup((SchemaAttributeGroup.Ref) entry.getValue());
673 }
674 for (Iterator it = _identityConstraints.entrySet().iterator(); it.hasNext(); )
675 {
676 Map.Entry entry = (Map.Entry) it.next();
677 String ns = ((QName) entry.getKey()).getNamespaceURI();
678 getContainerNonNull(ns).addIdentityConstraint((SchemaIdentityConstraint.Ref) entry.getValue());
679 }
680 for (Iterator it = _globalTypes.entrySet().iterator(); it.hasNext(); )
681 {
682 Map.Entry entry = (Map.Entry) it.next();
683 String ns = ((QName) entry.getKey()).getNamespaceURI();
684 getContainerNonNull(ns).addGlobalType((SchemaType.Ref) entry.getValue());
685 }
686 for (Iterator it = _documentTypes.entrySet().iterator(); it.hasNext(); )
687 {
688 Map.Entry entry = (Map.Entry) it.next();
689 String ns = ((QName) entry.getKey()).getNamespaceURI();
690 getContainerNonNull(ns).addDocumentType((SchemaType.Ref) entry.getValue());
691 }
692 for (Iterator it = _attributeTypes.entrySet().iterator(); it.hasNext(); )
693 {
694 Map.Entry entry = (Map.Entry) it.next();
695 String ns = ((QName) entry.getKey()).getNamespaceURI();
696 getContainerNonNull(ns).addAttributeType((SchemaType.Ref) entry.getValue());
697 }
698 // Some earlier .xsb versions don't have records for redefinitions
699 if (_redefinedGlobalTypes != null && _redefinedModelGroups != null &&
700 _redefinedAttributeGroups != null)
701 {
702 assert _redefinedGlobalTypes.size() == redefTypeNames.size();
703 for (Iterator it = _redefinedGlobalTypes.iterator(), itname = redefTypeNames.iterator(); it.hasNext(); )
704 {
705 String ns = ((QName) itname.next()).getNamespaceURI();
706 getContainerNonNull(ns).addRedefinedType((SchemaType.Ref) it.next());
707 }
708 for (Iterator it = _redefinedModelGroups.iterator(), itname = redefModelGroupNames.iterator(); it.hasNext(); )
709 {
710 String ns = ((QName) itname.next()).getNamespaceURI();
711 getContainerNonNull(ns).addRedefinedModelGroup((SchemaModelGroup.Ref) it.next());
712 }
713 for (Iterator it = _redefinedAttributeGroups.iterator(), itname = redefAttributeGroupNames.iterator(); it.hasNext(); )
714 {
715 String ns = ((QName) itname.next()).getNamespaceURI();
716 getContainerNonNull(ns).addRedefinedAttributeGroup((SchemaAttributeGroup.Ref) it.next());
717 }
718 }
719 // Some earlier .xsb versions don't have records for annotations
720 if (_annotations != null)
721 {
722 for (Iterator it = _annotations.iterator(); it.hasNext(); )
723 {
724 SchemaAnnotation ann = (SchemaAnnotation) it.next();
725 // BUGBUG(radup)
726 getContainerNonNull("").addAnnotation(ann);
727 }
728 }
729 for (Iterator it = _containers.values().iterator(); it.hasNext(); )
730 ((SchemaContainer) it.next()).setImmutable();
731 }
732
733 /**
734 * This is the crux of the container work and role.
735 * It makes a sweep over all containers and fixes each container's
736 * typesystem to point to this typesystem.
737 * Because SchemaComponents have a link to their containers, this has as
738 * effect all components now indirectly pointing to this typesystem
739 * even though they (as well as the typesystem itself) are immutable.
740 */
741 private void fixupContainers()
742 {
743 for (Iterator it = _containers.values().iterator(); it.hasNext(); )
744 {
745 SchemaContainer container = (SchemaContainer) it.next();
746 container.setTypeSystem(this);
747 container.setImmutable();
748 }
749 }
750
751 private void assertContainersSynchronized()
752 {
753 boolean assertEnabled = false;
754 // This code basically checks whether asserts are enabled so we don't do
755 // all the work if they arent
756 assert assertEnabled = true;
757 if (!assertEnabled)
758 return;
759 // global elements
760 Map temp = new HashMap();
761 for (Iterator it = _containers.values().iterator(); it.hasNext(); )
762 temp.putAll(buildComponentRefMap((SchemaComponent[]) ((SchemaContainer) it.next()).globalElements().toArray(new SchemaComponent[0])));
763 assert _globalElements.equals(temp);
764 // global attributes
765 temp = new HashMap();
766 for (Iterator it = _containers.values().iterator(); it.hasNext(); )
767 temp.putAll(buildComponentRefMap((SchemaComponent[]) ((SchemaContainer) it.next()).globalAttributes().toArray(new SchemaComponent[0])));
768 assert _globalAttributes.equals(temp);
769 // model groups
770 temp = new HashMap();
771 for (Iterator it = _containers.values().iterator(); it.hasNext(); )
772 temp.putAll(buildComponentRefMap((SchemaComponent[]) ((SchemaContainer) it.next()).modelGroups().toArray(new SchemaComponent[0])));
773 assert _modelGroups.equals(temp);
774 // redefined model groups
775 Set temp2 = new HashSet();
776 for (Iterator it = _containers.values().iterator(); it.hasNext(); )
777 temp2.addAll(buildComponentRefList((SchemaComponent[]) ((SchemaContainer) it.next()).redefinedModelGroups().toArray(new SchemaComponent[0])));
778 assert new HashSet(_redefinedModelGroups).equals(temp2);
779 // attribute groups
780 temp = new HashMap();
781 for (Iterator it = _containers.values().iterator(); it.hasNext(); )
782 temp.putAll(buildComponentRefMap((SchemaComponent[]) ((SchemaContainer) it.next()).attributeGroups().toArray(new SchemaComponent[0])));
783 assert _attributeGroups.equals(temp);
784 // redefined attribute groups
785 temp2 = new HashSet();
786 for (Iterator it = _containers.values().iterator(); it.hasNext(); )
787 temp2.addAll(buildComponentRefList((SchemaComponent[]) ((SchemaContainer) it.next()).redefinedAttributeGroups().toArray(new SchemaComponent[0])));
788 assert new HashSet(_redefinedAttributeGroups).equals(temp2);
789 // global types
790 temp = new HashMap();
791 for (Iterator it = _containers.values().iterator(); it.hasNext(); )
792 temp.putAll(buildComponentRefMap((SchemaComponent[]) ((SchemaContainer) it.next()).globalTypes().toArray(new SchemaComponent[0])));
793 assert _globalTypes.equals(temp);
794 // redefined global types
795 temp2 = new HashSet();
796 for (Iterator it = _containers.values().iterator(); it.hasNext(); )
797 temp2.addAll(buildComponentRefList((SchemaComponent[]) ((SchemaContainer) it.next()).redefinedGlobalTypes().toArray(new SchemaComponent[0])));
798 assert new HashSet(_redefinedGlobalTypes).equals(temp2);
799 // document types
800 temp = new HashMap();
801 for (Iterator it = _containers.values().iterator(); it.hasNext(); )
802 temp.putAll(buildDocumentMap((SchemaType[]) ((SchemaContainer) it.next()).documentTypes().toArray(new SchemaType[0])));
803 assert _documentTypes.equals(temp);
804 // attribute types
805 temp = new HashMap();
806 for (Iterator it = _containers.values().iterator(); it.hasNext(); )
807 temp.putAll(buildAttributeTypeMap((SchemaType[]) ((SchemaContainer) it.next()).attributeTypes().toArray(new SchemaType[0])));
808 assert _attributeTypes.equals(temp);
809 // identity constraints
810 temp = new HashMap();
811 for (Iterator it = _containers.values().iterator(); it.hasNext(); )
812 temp.putAll(buildComponentRefMap((SchemaComponent[]) ((SchemaContainer) it.next()).identityConstraints().toArray(new SchemaComponent[0])));
813 assert _identityConstraints.equals(temp);
814 // annotations
815 temp2 = new HashSet();
816 for (Iterator it = _containers.values().iterator(); it.hasNext(); )
817 temp2.addAll(((SchemaContainer) it.next()).annotations());
818 assert new HashSet(_annotations).equals(temp2);
819 // namespaces
820 temp2 = new HashSet();
821 for (Iterator it = _containers.values().iterator(); it.hasNext(); )
822 temp2.add(((SchemaContainer) it.next()).getNamespace());
823 assert _namespaces.equals(temp2);
824 }
825
826 private static Random _random;
827 private static byte[] _mask = new byte[128 / 8];
828
829 /**
830 * Fun, fun. Produce 128 bits of uniqueness randomly.
831 * We used to use SecureRandom, but now we don't because SecureRandom
832 * hits the filesystem and hangs us on a filesystem lock. It also eats
833 * a thread and other expensive resources.. :-).
834 *
835 * We don't really care that non-secure Random() can only do 48 bits of
836 * randomness, since we're certainly not going to be called more than 2^48
837 * times within our process lifetime.
838 *
839 * Our real concern is that by seeding Random() with the current
840 * time, two users will end up with the same bits if they start a
841 * schema compilation within the same millisecond. That makes the
842 * probability of collision in the real world slightly too high.
843 * We're going to have millions of users, remember? With a million
844 * users, and one-compilation-per-day each, we'd see a collision every
845 * few months.
846 *
847 * So we'll just xor the results of random with our few extra
848 * bits of information computed below to help reduce the probability
849 * of collision by a few decimal places. To collide, you will have had
850 * to have the same amount of free memory, the same user name, timezone,
851 * and country, the same current directory, the same java classpath,
852 * the same operating system and jvm version, and the same choices of
853 * identity hashcodes for a few objects. And be started within the same
854 * millisecond. Or you can collide if you have a cosmic 128-bit mathematical
855 * coincidence. No worries.
856 */
857 private static synchronized void nextBytes(byte[] result)
858 {
859 if (_random == null)
860 {
861 try
862 {
863 ByteArrayOutputStream baos = new ByteArrayOutputStream();
864 DataOutputStream daos = new DataOutputStream(baos);
865
866 // at least 10 bits of unqieueness, right? Maybe even 50 or 60.
867 daos.writeInt(System.identityHashCode(SchemaTypeSystemImpl.class));
868 String[] props = new String[] { "user.name", "user.dir", "user.timezone", "user.country", "java.class.path", "java.home", "java.vendor", "java.version", "os.version" };
869 for (int i = 0; i < props.length; i++)
870 {
871 String prop = SystemProperties.getProperty(props[i]);
872 if (prop != null)
873 {
874 daos.writeUTF(prop);
875 daos.writeInt(System.identityHashCode(prop));
876 }
877 }
878 daos.writeLong(Runtime.getRuntime().freeMemory());
879 daos.close();
880 byte[] bytes = baos.toByteArray();
881 for (int i = 0; i < bytes.length; i++)
882 {
883 int j = i % _mask.length;
884 _mask[j] *= 21;
885 _mask[j] += i;
886 }
887 }
888 catch (IOException e)
889 {
890 XBeanDebug.logException(e);
891 }
892
893 _random = new Random(System.currentTimeMillis());
894 }
895 _random.nextBytes(result);
896 for (int i = 0; i < result.length; i++)
897 {
898 int j = i & _mask.length;
899 result[i] ^= _mask[j];
900 }
901 }
902
903 public SchemaTypeSystemImpl(String nameForSystem)
904 {
905 // if we have no name, select a random one
906 if (nameForSystem == null)
907 {
908 // get 128 random bits (that'll be 32 hex digits)
909 byte[] bytes = new byte[128/8];
910 nextBytes(bytes);
911 nameForSystem = "s" + new String(HexBin.encode(bytes));
912 }
913
914 _name = "schema" + METADATA_PACKAGE_GEN + ".system." + nameForSystem;
915 _basePackage = nameToPathString(_name);
916 _classloader = null;
917
918 }
919
920 public void loadFromBuilder(SchemaGlobalElement[] globalElements,
921 SchemaGlobalAttribute[] globalAttributes,
922 SchemaType[] globalTypes,
923 SchemaType[] documentTypes,
924 SchemaType[] attributeTypes)
925 {
926 assert(_classloader == null);
927 _localHandles = new HandlePool();
928 _globalElements = buildComponentRefMap(globalElements);
929 _globalAttributes = buildComponentRefMap(globalAttributes);
930 _globalTypes = buildComponentRefMap(globalTypes);
931 _documentTypes = buildDocumentMap(documentTypes);
932 _attributeTypes = buildAttributeTypeMap(attributeTypes);
933 _typeRefsByClassname = buildTypeRefsByClassname();
934 buildContainers(Collections.EMPTY_LIST, Collections.EMPTY_LIST,
935 Collections.EMPTY_LIST);
936 _namespaces = new HashSet();
937 }
938
939 public void loadFromStscState(StscState state)
940 {
941 assert(_classloader == null);
942 _localHandles = new HandlePool();
943 _globalElements = buildComponentRefMap(state.globalElements());
944 _globalAttributes = buildComponentRefMap(state.globalAttributes());
945 _modelGroups = buildComponentRefMap(state.modelGroups());
946 _redefinedModelGroups = buildComponentRefList(state.redefinedModelGroups());
947 _attributeGroups = buildComponentRefMap(state.attributeGroups());
948 _redefinedAttributeGroups = buildComponentRefList(state.redefinedAttributeGroups());
949 _globalTypes = buildComponentRefMap(state.globalTypes());
950 _redefinedGlobalTypes = buildComponentRefList(state.redefinedGlobalTypes());
951 _documentTypes = buildDocumentMap(state.documentTypes());
952 _attributeTypes = buildAttributeTypeMap(state.attributeTypes());
953 _typeRefsByClassname = buildTypeRefsByClassname(state.typesByClassname());
954 _identityConstraints = buildComponentRefMap(state.idConstraints());
955 _annotations = state.annotations();
956 _namespaces = new HashSet(Arrays.asList(state.getNamespaces()));
957 _containers = state.getContainerMap();
958 fixupContainers();
959 // Checks that data in the containers matches the lookup maps
960 assertContainersSynchronized();
961 setDependencies(state.getDependencies());
962 }
963
964 final SchemaTypeSystemImpl getTypeSystem()
965 {
966 return this;
967 }
968
969 void setDependencies(SchemaDependencies deps)
970 { _deps = deps; }
971
972 SchemaDependencies getDependencies()
973 { return _deps; }
974
975 // EXPERIMENTAL
976 public boolean isIncomplete() { return _incomplete; }
977
978 // EXPERIMENTAL
979 void setIncomplete(boolean incomplete) { _incomplete = incomplete; }
980
981 static class StringPool
982 {
983 private List intsToStrings = new ArrayList();
984 private Map stringsToInts = new HashMap();
985 private String _handle;
986 private String _name;
987
988 /**
989 * Constructs an empty StringPool to be filled with strings.
990 */
991 StringPool(String handle, String name)
992 {
993 _handle = handle;
994 _name = name;
995 intsToStrings.add(null);
996 }
997
998 int codeForString(String str)
999 {
1000 if (str == null)
1001 return 0;
1002 Integer result = (Integer)stringsToInts.get(str);
1003 if (result == null)
1004 {
1005 result = new Integer(intsToStrings.size());
1006 intsToStrings.add(str);
1007 stringsToInts.put(str, result);
1008 }
1009 return result.intValue();
1010 }
1011
1012 String stringForCode(int code)
1013 {
1014 if (code == 0)
1015 return null;
1016 return (String)intsToStrings.get(code);
1017 }
1018
1019 void writeTo(DataOutputStream output)
1020 {
1021 if (intsToStrings.size() >= MAX_UNSIGNED_SHORT)
1022 throw new SchemaTypeLoaderException("Too many strings (" + intsToStrings.size() + ")", _name, _handle, SchemaTypeLoaderException.INT_TOO_LARGE);
1023
1024 try
1025 {
1026 output.writeShort(intsToStrings.size());
1027 Iterator i = intsToStrings.iterator();
1028 for (i.next(); i.hasNext(); )
1029 {
1030 String str = (String)i.next();
1031 output.writeUTF(str);
1032 }
1033 }
1034 catch (IOException e)
1035 {
1036 throw new SchemaTypeLoaderException(e.getMessage(), _name, _handle, SchemaTypeLoaderException.IO_EXCEPTION);
1037 }
1038 }
1039
1040 void readFrom(DataInputStream input)
1041 {
1042 if (intsToStrings.size() != 1 || stringsToInts.size() != 0)
1043 throw new IllegalStateException();
1044
1045 try
1046 {
1047 int size = input.readUnsignedShort();
1048 for (int i = 1; i < size; i++)
1049 {
1050 String str = input.readUTF().intern();
1051 int code = codeForString(str);
1052 if (code != i)
1053 throw new IllegalStateException();
1054 }
1055 }
1056 catch (IOException e)
1057 {
1058 throw new SchemaTypeLoaderException(e.getMessage() == null ? e.getMessage() : "IO Exception", _name, _handle, SchemaTypeLoaderException.IO_EXCEPTION, e);
1059 }
1060 }
1061 }
1062
1063 class HandlePool
1064 {
1065 private Map _handlesToRefs = new LinkedHashMap();
1066 private Map _componentsToHandles = new LinkedHashMap(); // populated on write
1067 private boolean _started;
1068
1069 /**
1070 * Constructs an empty HandlePool to be populated.
1071 */
1072 HandlePool()
1073 {
1074 }
1075
1076 private String addUniqueHandle(SchemaComponent obj, String base)
1077 {
1078 base = base.toLowerCase(); // we lowercase handles because of case-insensitive Windows filenames!!!
1079 String handle = base;
1080 for (int index = 2; _handlesToRefs.containsKey(handle); index++)
1081 {
1082 handle = base + index;
1083 }
1084 _handlesToRefs.put(handle, obj.getComponentRef());
1085 _componentsToHandles.put(obj, handle);
1086 return handle;
1087 }
1088
1089 String handleForComponent(SchemaComponent comp)
1090 {
1091 if (comp == null)
1092 return null;
1093 if (comp.getTypeSystem() != getTypeSystem())
1094 throw new IllegalArgumentException("Cannot supply handles for types from another type system");
1095 if (comp instanceof SchemaType)
1096 return handleForType((SchemaType)comp);
1097 if (comp instanceof SchemaGlobalElement)
1098 return handleForElement((SchemaGlobalElement)comp);
1099 if (comp instanceof SchemaGlobalAttribute)
1100 return handleForAttribute((SchemaGlobalAttribute)comp);
1101 if (comp instanceof SchemaModelGroup)
1102 return handleForModelGroup((SchemaModelGroup)comp);
1103 if (comp instanceof SchemaAttributeGroup)
1104 return handleForAttributeGroup((SchemaAttributeGroup)comp);
1105 if (comp instanceof SchemaIdentityConstraint)
1106 return handleForIdentityConstraint((SchemaIdentityConstraint)comp);
1107 throw new IllegalStateException("Component type cannot have a handle");
1108 }
1109
1110 String handleForElement(SchemaGlobalElement element)
1111 {
1112 if (element == null)
1113 return null;
1114 if (element.getTypeSystem() != getTypeSystem())
1115 throw new IllegalArgumentException("Cannot supply handles for types from another type system");
1116 String handle = (String)_componentsToHandles.get(element);
1117 if (handle == null)
1118 handle = addUniqueHandle(element, NameUtil.upperCamelCase(element.getName().getLocalPart()) + "Element");
1119 return handle;
1120 }
1121
1122 String handleForAttribute(SchemaGlobalAttribute attribute)
1123 {
1124 if (attribute == null)
1125 return null;
1126 if (attribute.getTypeSystem() != getTypeSystem())
1127 throw new IllegalArgumentException("Cannot supply handles for types from another type system");
1128 String handle = (String)_componentsToHandles.get(attribute);
1129 if (handle == null)
1130 handle = addUniqueHandle(attribute, NameUtil.upperCamelCase(attribute.getName().getLocalPart()) + "Attribute");
1131 return handle;
1132 }
1133
1134 String handleForModelGroup(SchemaModelGroup group)
1135 {
1136 if (group == null)
1137 return null;
1138 if (group.getTypeSystem() != getTypeSystem())
1139 throw new IllegalArgumentException("Cannot supply handles for types from another type system");
1140 String handle = (String)_componentsToHandles.get(group);
1141 if (handle == null)
1142 handle = addUniqueHandle(group, NameUtil.upperCamelCase(group.getName().getLocalPart()) + "ModelGroup");
1143 return handle;
1144 }
1145
1146 String handleForAttributeGroup(SchemaAttributeGroup group)
1147 {
1148 if (group == null)
1149 return null;
1150 if (group.getTypeSystem() != getTypeSystem())
1151 throw new IllegalArgumentException("Cannot supply handles for types from another type system");
1152 String handle = (String)_componentsToHandles.get(group);
1153 if (handle == null)
1154 handle = addUniqueHandle(group, NameUtil.upperCamelCase(group.getName().getLocalPart()) + "AttributeGroup");
1155 return handle;
1156 }
1157
1158 String handleForIdentityConstraint(SchemaIdentityConstraint idc)
1159 {
1160 if (idc == null)
1161 return null;
1162 if (idc.getTypeSystem() != getTypeSystem())
1163 throw new IllegalArgumentException("Cannot supply handles for types from another type system");
1164 String handle = (String)_componentsToHandles.get(idc);
1165 if (handle == null)
1166 handle = addUniqueHandle(idc, NameUtil.upperCamelCase(idc.getName().getLocalPart()) + "IdentityConstraint");
1167 return handle;
1168 }
1169
1170 String handleForType(SchemaType type)
1171 {
1172 if (type == null)
1173 return null;
1174 if (type.getTypeSystem() != getTypeSystem())
1175 throw new IllegalArgumentException("Cannot supply handles for types from another type system");
1176 String handle = (String)_componentsToHandles.get(type);
1177 if (handle == null)
1178 {
1179 QName name = type.getName();
1180 String suffix = "";
1181 if (name == null)
1182 {
1183 if (type.isDocumentType())
1184 {
1185 name = type.getDocumentElementName();
1186 suffix = "Doc";
1187 }
1188 else if (type.isAttributeType())
1189 {
1190 name = type.getAttributeTypeAttributeName();
1191 suffix = "AttrType";
1192 }
1193 else if (type.getContainerField() != null)
1194 {
1195 name = type.getContainerField().getName();
1196 suffix = type.getContainerField().isAttribute() ? "Attr" : "Elem";
1197 }
1198 }
1199
1200 String baseName;
1201 String uniq = Integer.toHexString(type.toString().hashCode() | 0x80000000).substring(4).toUpperCase();
1202 if (name == null)
1203 baseName = "Anon" + uniq + "Type";
1204 else
1205 baseName = NameUtil.upperCamelCase(name.getLocalPart()) + uniq + suffix + "Type";
1206
1207 handle = addUniqueHandle(type, baseName);
1208 }
1209
1210 return handle;
1211 }
1212
1213 SchemaComponent.Ref refForHandle(String handle)
1214 {
1215 if (handle == null)
1216 return null;
1217
1218 return (SchemaComponent.Ref)_handlesToRefs.get(handle);
1219 }
1220
1221 Set getAllHandles()
1222 {
1223 return _handlesToRefs.keySet();
1224 }
1225
1226 void startWriteMode()
1227 {
1228 _started = true;
1229 _componentsToHandles = new LinkedHashMap();
1230 for (Iterator i = _handlesToRefs.keySet().iterator(); i.hasNext(); )
1231 {
1232 String handle = (String)i.next();
1233 // System.err.println("Writing preexisting handle " + handle);
1234 SchemaComponent comp = ((SchemaComponent.Ref)_handlesToRefs.get(handle)).getComponent();
1235 _componentsToHandles.put(comp, handle);
1236 }
1237 }
1238
1239 }
1240
1241 private String _name;
1242 private String _basePackage;
1243
1244 // EXPERIMENTAL: recovery from compilation errors and partial type systems
1245 private boolean _incomplete = false;
1246
1247 // classloader is available for sts's that were compiled and loaded, not dynamic ones
1248 private ClassLoader _classloader;
1249
1250 // the loader for loading .xsb resources
1251 private ResourceLoader _resourceLoader;
1252
1253 // the following is used to link references during load
1254 SchemaTypeLoader _linker;
1255
1256 private HandlePool _localHandles;
1257 private Filer _filer;
1258
1259 // top-level annotations
1260 private List _annotations;
1261
1262 // container
1263 private Map _containers = new HashMap();
1264 // dependencies
1265 private SchemaDependencies _deps;
1266
1267 private List _redefinedModelGroups;
1268 private List _redefinedAttributeGroups;
1269 private List _redefinedGlobalTypes;
1270
1271 // actual type system data, map QNames -> SchemaComponent.Ref
1272 private Map _globalElements;
1273 private Map _globalAttributes;
1274 private Map _modelGroups;
1275 private Map _attributeGroups;
1276 private Map _globalTypes;
1277 private Map _documentTypes;
1278 private Map _attributeTypes;
1279 private Map _identityConstraints = Collections.EMPTY_MAP;
1280 private Map _typeRefsByClassname = new HashMap();
1281 private Set _namespaces;
1282
1283 static private final SchemaType[] EMPTY_ST_ARRAY = new SchemaType[0];
1284 static private final SchemaGlobalElement[] EMPTY_GE_ARRAY = new SchemaGlobalElement[0];
1285 static private final SchemaGlobalAttribute[] EMPTY_GA_ARRAY = new SchemaGlobalAttribute[0];
1286 static private final SchemaModelGroup[] EMPTY_MG_ARRAY = new SchemaModelGroup[0];
1287 static private final SchemaAttributeGroup[] EMPTY_AG_ARRAY = new SchemaAttributeGroup[0];
1288 static private final SchemaIdentityConstraint[] EMPTY_IC_ARRAY = new SchemaIdentityConstraint[0];
1289 static private final SchemaAnnotation[] EMPTY_ANN_ARRAY = new SchemaAnnotation[0];
1290
1291 public void saveToDirectory(File classDir)
1292 {
1293 save(new FilerImpl(classDir, null, null, false, false));
1294 }
1295
1296 public void save(Filer filer)
1297 {
1298 if (_incomplete)
1299 throw new IllegalStateException("Incomplete SchemaTypeSystems cannot be saved.");
1300
1301 if (filer == null)
1302 throw new IllegalArgumentException("filer must not be null");
1303 _filer = filer;
1304
1305 _localHandles.startWriteMode();
1306 saveTypesRecursively(globalTypes());
1307 saveTypesRecursively(documentTypes());
1308 saveTypesRecursively(attributeTypes());
1309 saveGlobalElements(globalElements());
1310 saveGlobalAttributes(globalAttributes());
1311 saveModelGroups(modelGroups());
1312 saveAttributeGroups(attributeGroups());
1313 saveIdentityConstraints(identityConstraints());
1314
1315 saveTypesRecursively(redefinedGlobalTypes());
1316 saveModelGroups(redefinedModelGroups());
1317 saveAttributeGroups(redefinedAttributeGroups());
1318
1319 saveIndex();
1320 savePointers();
1321
1322 saveLoader();
1323 }
1324
1325 void saveTypesRecursively(SchemaType[] types)
1326 {
1327 for (int i = 0; i < types.length; i++)
1328 {
1329 if (types[i].getTypeSystem() != getTypeSystem())
1330 continue;
1331 saveType(types[i]);
1332 saveTypesRecursively(types[i].getAnonymousTypes());
1333 }
1334 }
1335
1336 public void saveGlobalElements(SchemaGlobalElement[] elts)
1337 {
1338 if (_incomplete)
1339 throw new IllegalStateException("This SchemaTypeSystem cannot be saved.");
1340 for (int i = 0; i < elts.length; i++)
1341 {
1342 saveGlobalElement(elts[i]);
1343 }
1344 }
1345
1346 public void saveGlobalAttributes(SchemaGlobalAttribute[] attrs)
1347 {
1348 if (_incomplete)
1349 throw new IllegalStateException("This SchemaTypeSystem cannot be saved.");
1350 for (int i = 0; i < attrs.length; i++)
1351 {
1352 saveGlobalAttribute(attrs[i]);
1353 }
1354 }
1355
1356 public void saveModelGroups(SchemaModelGroup[] groups)
1357 {
1358 if (_incomplete)
1359 throw new IllegalStateException("This SchemaTypeSystem cannot be saved.");
1360 for (int i = 0; i < groups.length; i++)
1361 {
1362 saveModelGroup(groups[i]);
1363 }
1364 }
1365
1366 public void saveAttributeGroups(SchemaAttributeGroup[] groups)
1367 {
1368 if (_incomplete)
1369 throw new IllegalStateException("This SchemaTypeSystem cannot be saved.");
1370 for (int i = 0; i < groups.length; i++)
1371 {
1372 saveAttributeGroup(groups[i]);
1373 }
1374 }
1375
1376 public void saveIdentityConstraints(SchemaIdentityConstraint[] idcs)
1377 {
1378 if (_incomplete)
1379 throw new IllegalStateException("This SchemaTypeSystem cannot be saved.");
1380 for (int i = 0; i < idcs.length; i++)
1381 {
1382 saveIdentityConstraint(idcs[i]);
1383 }
1384 }
1385
1386 public void saveGlobalElement(SchemaGlobalElement elt)
1387 {
1388 if (_incomplete)
1389 throw new IllegalStateException("This SchemaTypeSystem cannot be saved.");
1390 String handle = _localHandles.handleForElement(elt);
1391 XsbReader saver = new XsbReader(handle);
1392 saver.writeParticleData((SchemaParticle)elt);
1393 saver.writeString(elt.getSourceName());
1394 saver.writeRealHeader(handle, FILETYPE_SCHEMAELEMENT);
1395 saver.writeParticleData((SchemaParticle)elt);
1396 saver.writeString(elt.getSourceName());
1397 saver.writeEnd();
1398 }
1399
1400 public void saveGlobalAttribute(SchemaGlobalAttribute attr)
1401 {
1402 if (_incomplete)
1403 throw new IllegalStateException("This SchemaTypeSystem cannot be saved.");
1404 String handle = _localHandles.handleForAttribute(attr);
1405 XsbReader saver = new XsbReader(handle);
1406 saver.writeAttributeData(attr);
1407 saver.writeString(attr.getSourceName());
1408 saver.writeRealHeader(handle, FILETYPE_SCHEMAATTRIBUTE);
1409 saver.writeAttributeData(attr);
1410 saver.writeString(attr.getSourceName());
1411 saver.writeEnd();
1412 }
1413
1414 public void saveModelGroup(SchemaModelGroup grp)
1415 {
1416 if (_incomplete)
1417 throw new IllegalStateException("This SchemaTypeSystem cannot be saved.");
1418 String handle = _localHandles.handleForModelGroup(grp);
1419 XsbReader saver = new XsbReader(handle);
1420 saver.writeModelGroupData(grp);
1421 saver.writeRealHeader(handle, FILETYPE_SCHEMAMODELGROUP);
1422 saver.writeModelGroupData(grp);
1423 saver.writeEnd();
1424 }
1425
1426 public void saveAttributeGroup(SchemaAttributeGroup grp)
1427 {
1428 if (_incomplete)
1429 throw new IllegalStateException("This SchemaTypeSystem cannot be saved.");
1430 String handle = _localHandles.handleForAttributeGroup(grp);
1431 XsbReader saver = new XsbReader(handle);
1432 saver.writeAttributeGroupData(grp);
1433 saver.writeRealHeader(handle, FILETYPE_SCHEMAATTRIBUTEGROUP);
1434 saver.writeAttributeGroupData(grp);
1435 saver.writeEnd();
1436 }
1437
1438 public void saveIdentityConstraint(SchemaIdentityConstraint idc)
1439 {
1440 if (_incomplete)
1441 throw new IllegalStateException("This SchemaTypeSystem cannot be saved.");
1442 String handle = _localHandles.handleForIdentityConstraint(idc);
1443 XsbReader saver = new XsbReader(handle);
1444 saver.writeIdConstraintData(idc);
1445 saver.writeRealHeader(handle, FILETYPE_SCHEMAIDENTITYCONSTRAINT);
1446 saver.writeIdConstraintData(idc);
1447 saver.writeEnd();
1448 }
1449
1450 void saveType(SchemaType type)
1451 {
1452 String handle = _localHandles.handleForType(type);
1453 XsbReader saver = new XsbReader(handle);
1454 saver.writeTypeData(type);
1455 saver.writeRealHeader(handle, FILETYPE_SCHEMATYPE);
1456 saver.writeTypeData(type);
1457 saver.writeEnd();
1458 }
1459
1460 public static String crackPointer(InputStream stream)
1461 {
1462 DataInputStream input = null;
1463 try
1464 {
1465 input = new DataInputStream(stream);
1466
1467 int magic = input.readInt();
1468 if (magic != DATA_BABE)
1469 return null;
1470
1471 int majorver = input.readShort();
1472 int minorver = input.readShort();
1473
1474 if (majorver != MAJOR_VERSION)
1475 return null;
1476
1477 if (minorver > MINOR_VERSION)
1478 return null;
1479
1480 if (majorver > 2 || majorver == 2 && minorver >= 18)
1481 input.readShort(); // release number present in atLeast(2, 18, 0)
1482
1483 int actualfiletype = input.readShort();
1484 if (actualfiletype != FILETYPE_SCHEMAPOINTER)
1485 return null;
1486
1487 StringPool stringPool = new StringPool("pointer", "unk");
1488 stringPool.readFrom(input);
1489
1490 return stringPool.stringForCode(input.readShort());
1491 }
1492 catch (IOException e)
1493 {
1494 return null;
1495 }
1496 finally
1497 {
1498 if (input != null)
1499 try { input.close(); } catch (IOException e) {}
1500 }
1501 }
1502
1503 private class XsbReader
1504 {
1505 DataInputStream _input;
1506 DataOutputStream _output;
1507 StringPool _stringPool;
1508 String _handle;
1509 private int _majorver;
1510 private int _minorver;
1511 private int _releaseno;
1512 int _actualfiletype;
1513
1514 public XsbReader(String handle, int filetype)
1515 {
1516 String resourcename = _basePackage + handle + ".xsb";
1517 InputStream rawinput = getLoaderStream(resourcename);
1518 if (rawinput == null)
1519 throw new SchemaTypeLoaderException("XML-BEANS compiled schema: Could not locate compiled schema resource " + resourcename, _name, handle, SchemaTypeLoaderException.NO_RESOURCE);
1520
1521 _input = new DataInputStream(rawinput);
1522 _handle = handle;
1523
1524 int magic = readInt();
1525 if (magic != DATA_BABE)
1526 throw new SchemaTypeLoaderException("XML-BEANS compiled schema: Wrong magic cookie", _name, handle, SchemaTypeLoaderException.WRONG_MAGIC_COOKIE);
1527
1528 _majorver = readShort();
1529 _minorver = readShort();
1530
1531 if (_majorver != MAJOR_VERSION)
1532 throw new SchemaTypeLoaderException("XML-BEANS compiled schema: Wrong major version - expecting " + MAJOR_VERSION + ", got " + _majorver, _name, handle, SchemaTypeLoaderException.WRONG_MAJOR_VERSION);
1533
1534 if (_minorver > MINOR_VERSION)
1535 throw new SchemaTypeLoaderException("XML-BEANS compiled schema: Incompatible minor version - expecting up to " + MINOR_VERSION + ", got " + _minorver, _name, handle, SchemaTypeLoaderException.WRONG_MINOR_VERSION);
1536
1537 // Clip to 14 because we're not backward compatible with earlier
1538 // minor versions. Remove this when upgrading to a new major
1539 // version
1540
1541 if (_minorver < 14)
1542 throw new SchemaTypeLoaderException("XML-BEANS compiled schema: Incompatible minor version - expecting at least 14, got " + _minorver, _name, handle, SchemaTypeLoaderException.WRONG_MINOR_VERSION);
1543
1544 if (atLeast(2, 18, 0))
1545 _releaseno = readShort();
1546
1547 int actualfiletype = readShort();
1548 if (actualfiletype != filetype && filetype != 0xFFFF)
1549 throw new SchemaTypeLoaderException("XML-BEANS compiled schema: File has the wrong type - expecting type " + filetype + ", got type " + actualfiletype, _name, handle, SchemaTypeLoaderException.WRONG_FILE_TYPE);
1550
1551 _stringPool = new StringPool(_handle, _name);
1552 _stringPool.readFrom(_input);
1553
1554 _actualfiletype = actualfiletype;
1555 }
1556
1557 protected boolean atLeast(int majorver, int minorver, int releaseno)
1558 {
1559 if (_majorver > majorver)
1560 return true;
1561 if (_majorver < majorver)
1562 return false;
1563 if (_minorver > minorver)
1564 return true;
1565 if (_minorver < minorver)
1566 return false;
1567 return (_releaseno >= releaseno);
1568 }
1569
1570 protected boolean atMost(int majorver, int minorver, int releaseno)
1571 {
1572 if (_majorver > majorver)
1573 return false;
1574 if (_majorver < majorver)
1575 return true;
1576 if (_minorver > minorver)
1577 return false;
1578 if (_minorver < minorver)
1579 return true;
1580 return (_releaseno <= releaseno);
1581 }
1582
1583 int getActualFiletype()
1584 {
1585 return _actualfiletype;
1586 }
1587
1588 XsbReader(String handle)
1589 {
1590 _handle = handle;
1591 _stringPool = new StringPool(_handle, _name);
1592 }
1593
1594 void writeRealHeader(String handle, int filetype)
1595 {
1596 // hackeroo: if handle contains a "/" it's not relative.
1597 String resourcename;
1598
1599 if (handle.indexOf('/') >= 0)
1600 resourcename = handle + ".xsb";
1601 else
1602 resourcename = _basePackage + handle + ".xsb";
1603
1604 OutputStream rawoutput = getSaverStream(resourcename);
1605 if (rawoutput == null)
1606 throw new SchemaTypeLoaderException("Could not write compiled schema resource " + resourcename, _name, handle, SchemaTypeLoaderException.NOT_WRITEABLE);
1607
1608 _output = new DataOutputStream(rawoutput);
1609 _handle = handle;
1610
1611 writeInt(DATA_BABE);
1612 writeShort(MAJOR_VERSION);
1613 writeShort(MINOR_VERSION);
1614 writeShort(RELEASE_NUMBER);
1615 writeShort(filetype);
1616
1617 _stringPool.writeTo(_output);
1618 }
1619
1620 void readEnd()
1621 {
1622 try
1623 {
1624 if (_input != null)
1625 _input.close();
1626 }
1627 catch (IOException e)
1628 {
1629 // oh, well.
1630 }
1631 _input = null;
1632 _stringPool = null;
1633 _handle = null;
1634 }
1635
1636 void writeEnd()
1637 {
1638 try
1639 {
1640 if (_output != null)
1641 {
1642 _output.flush();
1643 _output.close();
1644 }
1645 }
1646 catch (IOException e)
1647 {
1648 throw new SchemaTypeLoaderException(e.getMessage(), _name, _handle, SchemaTypeLoaderException.IO_EXCEPTION);
1649 }
1650 _output = null;
1651 _stringPool = null;
1652 _handle = null;
1653 }
1654
1655 int fileTypeFromComponentType(int componentType)
1656 {
1657 switch (componentType)
1658 {
1659 case SchemaComponent.TYPE:
1660 return SchemaTypeSystemImpl.FILETYPE_SCHEMATYPE;
1661 case SchemaComponent.ELEMENT:
1662 return SchemaTypeSystemImpl.FILETYPE_SCHEMAELEMENT;
1663 case SchemaComponent.ATTRIBUTE:
1664 return SchemaTypeSystemImpl.FILETYPE_SCHEMAATTRIBUTE;
1665 case SchemaComponent.MODEL_GROUP:
1666 return SchemaTypeSystemImpl.FILETYPE_SCHEMAMODELGROUP;
1667 case SchemaComponent.ATTRIBUTE_GROUP:
1668 return SchemaTypeSystemImpl.FILETYPE_SCHEMAATTRIBUTEGROUP;
1669 case SchemaComponent.IDENTITY_CONSTRAINT:
1670 return SchemaTypeSystemImpl.FILETYPE_SCHEMAIDENTITYCONSTRAINT;
1671 default:
1672 throw new IllegalStateException("Unexpected component type");
1673 }
1674 }
1675
1676 void writeIndexData()
1677 {
1678 // has a handle pool (count, handle/type, handle/type...)
1679 writeHandlePool(_localHandles);
1680
1681 // then a qname map of global elements (count, qname/handle, qname/handle...)
1682 writeQNameMap(globalElements());
1683
1684 // qname map of global attributes
1685 writeQNameMap(globalAttributes());
1686
1687 // qname map of model groups
1688 writeQNameMap(modelGroups());
1689
1690 // qname map of attribute groups
1691 writeQNameMap(attributeGroups());
1692
1693 // qname map of identity constraints
1694 writeQNameMap(identityConstraints());
1695
1696 // qname map of global types
1697 writeQNameMap(globalTypes());
1698
1699 // qname map of document types, by the qname of the contained element
1700 writeDocumentTypeMap(documentTypes());
1701
1702 // qname map of attribute types, by the qname of the contained attribute
1703 writeAttributeTypeMap(attributeTypes());
1704
1705 // all the types by classname
1706 writeClassnameMap(_typeRefsByClassname);
1707
1708 // all the namespaces
1709 writeNamespaces(_namespaces);
1710
1711 // VERSION 2.15 and newer below
1712 writeQNameMap(redefinedGlobalTypes());
1713 writeQNameMap(redefinedModelGroups());
1714 writeQNameMap(redefinedAttributeGroups());
1715 writeAnnotations(annotations());
1716 }
1717
1718 void writeHandlePool(HandlePool pool)
1719 {
1720 writeShort(pool._componentsToHandles.size());
1721 for (Iterator i = pool._componentsToHandles.keySet().iterator(); i.hasNext(); )
1722 {
1723 SchemaComponent comp = (SchemaComponent)i.next();
1724 String handle = (String)pool._componentsToHandles.get(comp);
1725 int code = fileTypeFromComponentType(comp.getComponentType());
1726 writeString(handle);
1727 writeShort(code);
1728 }
1729 }
1730
1731 void readHandlePool(HandlePool pool)
1732 {
1733 if (pool._handlesToRefs.size() != 0 || pool._started)
1734 throw new IllegalStateException("Nonempty handle set before read");
1735
1736 int size = readShort();
1737 for (int i = 0; i < size; i++)
1738 {
1739 String handle = readString();
1740 int code = readShort();
1741 Object result;
1742 switch (code)
1743 {
1744 case FILETYPE_SCHEMATYPE:
1745 result = new SchemaType.Ref(getTypeSystem(), handle);
1746 break;
1747 case FILETYPE_SCHEMAELEMENT:
1748 result = new SchemaGlobalElement.Ref(getTypeSystem(), handle);
1749 break;
1750 case FILETYPE_SCHEMAATTRIBUTE:
1751 result = new SchemaGlobalAttribute.Ref(getTypeSystem(), handle);
1752 break;
1753 case FILETYPE_SCHEMAMODELGROUP:
1754 result = new SchemaModelGroup.Ref(getTypeSystem(), handle);
1755 break;
1756 case FILETYPE_SCHEMAATTRIBUTEGROUP:
1757 result = new SchemaAttributeGroup.Ref(getTypeSystem(), handle);
1758 break;
1759 case FILETYPE_SCHEMAIDENTITYCONSTRAINT:
1760 result = new SchemaIdentityConstraint.Ref(getTypeSystem(), handle);
1761 break;
1762 default:
1763 throw new SchemaTypeLoaderException("Schema index has an unrecognized entry of type " + code, _name, handle, SchemaTypeLoaderException.UNRECOGNIZED_INDEX_ENTRY);
1764 }
1765 pool._handlesToRefs.put(handle, result);
1766 }
1767 }
1768
1769 int readShort()
1770 {
1771 try
1772 {
1773 return _input.readUnsignedShort();
1774 }
1775 catch (IOException e)
1776 {
1777 throw new SchemaTypeLoaderException(e.getMessage(), _name, _handle, SchemaTypeLoaderException.IO_EXCEPTION);
1778 }
1779 }
1780
1781 void writeShort(int s)
1782 {
1783 if (s >= MAX_UNSIGNED_SHORT || s < -1)
1784 throw new SchemaTypeLoaderException("Value " + s + " out of range: must fit in a 16-bit unsigned short.", _name, _handle, SchemaTypeLoaderException.INT_TOO_LARGE);
1785 if (_output != null)
1786 {
1787 try
1788 {
1789 _output.writeShort(s);
1790 }
1791 catch (IOException e)
1792 {
1793 throw new SchemaTypeLoaderException(e.getMessage(), _name, _handle, SchemaTypeLoaderException.IO_EXCEPTION);
1794 }
1795 }
1796 }
1797
1798 int readInt()
1799 {
1800 try
1801 {
1802 return _input.readInt();
1803 }
1804 catch (IOException e)
1805 {
1806 throw new SchemaTypeLoaderException(e.getMessage(), _name, _handle, SchemaTypeLoaderException.IO_EXCEPTION);
1807 }
1808 }
1809
1810 void writeInt(int i)
1811 {
1812 if (_output != null)
1813 {
1814 try
1815 {
1816 _output.writeInt(i);
1817 }
1818 catch (IOException e)
1819 {
1820 throw new SchemaTypeLoaderException(e.getMessage(), _name, _handle, SchemaTypeLoaderException.IO_EXCEPTION);
1821 }
1822 }
1823 }
1824
1825 String readString()
1826 {
1827 return _stringPool.stringForCode(readShort());
1828 }
1829
1830 void writeString(String str)
1831 {
1832 int code = _stringPool.codeForString(str);
1833 writeShort(code);
1834 }
1835
1836 QName readQName()
1837 {
1838 String namespace = readString();
1839 String localname = readString();
1840 if (localname == null)
1841 return null;
1842 return new QName(namespace, localname);
1843 }
1844
1845 void writeQName(QName qname)
1846 {
1847 if (qname == null)
1848 {
1849 writeString(null);
1850 writeString(null);
1851 return;
1852 }
1853 writeString(qname.getNamespaceURI());
1854 writeString(qname.getLocalPart());
1855 }
1856
1857 SOAPArrayType readSOAPArrayType()
1858 {
1859 QName qName = readQName();
1860 String dimensions = readString();
1861 if (qName == null)
1862 return null;
1863 return new SOAPArrayType(qName, dimensions);
1864 }
1865
1866 void writeSOAPArrayType(SOAPArrayType arrayType)
1867 {
1868 if (arrayType == null)
1869 {
1870 writeQName(null);
1871 writeString(null);
1872 }
1873 else
1874 {
1875 writeQName(arrayType.getQName());
1876 writeString(arrayType.soap11DimensionString());
1877 }
1878 }
1879
1880 void writeAnnotation(SchemaAnnotation a)
1881 {
1882 // Write attributes
1883 if (a == null)
1884 {
1885 writeInt(-1);
1886 return;
1887 }
1888 SchemaAnnotation.Attribute[] attributes = a.getAttributes();
1889 writeInt(attributes.length);
1890 for (int i = 0; i < attributes.length; i++)
1891 {
1892 QName name = attributes[i].getName();
1893 String value = attributes[i].getValue();
1894 String valueURI = attributes[i].getValueUri();
1895 writeQName(name);
1896 writeString(value);
1897 writeString(valueURI);
1898 }
1899
1900 // Write documentation items
1901 XmlObject[] documentationItems = a.getUserInformation();
1902 writeInt(documentationItems.length);
1903 XmlOptions opt = new XmlOptions().setSaveOuter().
1904 setSaveAggressiveNamespaces();
1905 for (int i = 0; i < documentationItems.length; i++)
1906 {
1907 XmlObject doc = documentationItems[i];
1908 writeString(doc.xmlText(opt));
1909 }
1910
1911 // Write application info items
1912 XmlObject[] appInfoItems = a.getApplicationInformation();
1913 writeInt(appInfoItems.length);
1914 for (int i = 0; i < appInfoItems.length; i++)
1915 {
1916 XmlObject doc = appInfoItems[i];
1917 writeString(doc.xmlText(opt));
1918 }
1919 }
1920
1921 SchemaAnnotation readAnnotation(SchemaContainer c)
1922 {
1923 if (!atLeast(2, 19, 0))
1924 return null; // no annotations for this version of the file
1925 // Read attributes
1926 int n = readInt();
1927 if (n == -1)
1928 return null;
1929 SchemaAnnotation.Attribute[] attributes =
1930 new SchemaAnnotation.Attribute[n];
1931 for (int i = 0; i < n; i++)
1932 {
1933 QName name = readQName();
1934 String value = readString();
1935 String valueUri = null;
1936 if (atLeast(2, 24, 0))
1937 valueUri = readString();
1938 attributes[i] = new SchemaAnnotationImpl.AttributeImpl(name, value, valueUri);
1939 }
1940
1941 // Read documentation items
1942 n = readInt();
1943 String[] docStrings = new String[n];
1944 for (int i = 0; i < n; i++)
1945 {
1946 docStrings[i] = readString();
1947 }
1948
1949 // Read application info items
1950 n = readInt();
1951 String[] appInfoStrings = new String[n];
1952 for (int i = 0; i < n; i++)
1953 {
1954 appInfoStrings[i] = readString();
1955 }
1956
1957 return new SchemaAnnotationImpl(c, appInfoStrings,
1958 docStrings, attributes);
1959 }
1960
1961 void writeAnnotations(SchemaAnnotation[] anns)
1962 {
1963 writeInt(anns.length);
1964 for (int i = 0; i < anns.length; i++)
1965 writeAnnotation(anns[i]);
1966 }
1967
1968 List readAnnotations()
1969 {
1970 int n = readInt();
1971 List result = new ArrayList(n);
1972 // BUGBUG(radup)
1973 SchemaContainer container = getContainerNonNull("");
1974 for (int i = 0; i < n; i++)
1975 result.add(readAnnotation(container));
1976 return result;
1977 }
1978
1979 SchemaComponent.Ref readHandle()
1980 {
1981 String handle = readString();
1982 if (handle == null)
1983 return null;
1984
1985 if (handle.charAt(0) != '_')
1986 return _localHandles.refForHandle(handle);
1987
1988 switch (handle.charAt(2))
1989 {
1990 case 'I': // _BI_ - built-in schema type system
1991 return ((SchemaType)BuiltinSchemaTypeSystem.get().resolveHandle(handle)).getRef();
1992 case 'T': // _XT_ - external type
1993 return _linker.findTypeRef(QNameHelper.forPretty(handle, 4));
1994 case 'E': // _XE_ - external element
1995 return _linker.findElementRef(QNameHelper.forPretty(handle, 4));
1996 case 'A': // _XA_ - external attribute
1997 return _linker.findAttributeRef(QNameHelper.forPretty(handle, 4));
1998 case 'M': // _XM_ - external model group
1999 return _linker.findModelGroupRef(QNameHelper.forPretty(handle, 4));
2000 case 'N': // _XN_ - external attribute group
2001 return _linker.findAttributeGroupRef(QNameHelper.forPretty(handle, 4));
2002 case 'D': // _XD_ - external identity constraint
2003 return _linker.findIdentityConstraintRef(QNameHelper.forPretty(handle, 4));
2004 case 'R': // _XR_ - external ref to attribute's type
2005 // deprecated: replaced by _XY_
2006 SchemaGlobalAttribute attr = _linker.findAttribute(QNameHelper.forPretty(handle, 4));
2007 if (attr == null)
2008 throw new SchemaTypeLoaderException("Cannot resolve attribute for handle " + handle, _name, _handle, SchemaTypeLoaderException.BAD_HANDLE);
2009 return attr.getType().getRef();
2010 case 'S': // _XS_ - external ref to element's type
2011 // deprecated: replaced by _XY_
2012 SchemaGlobalElement elem = _linker.findElement(QNameHelper.forPretty(handle, 4));
2013 if (elem == null)
2014 throw new SchemaTypeLoaderException("Cannot resolve element for handle " + handle, _name, _handle, SchemaTypeLoaderException.BAD_HANDLE);
2015 return elem.getType().getRef();
2016 case 'O': // _XO_ - external ref to document type
2017 return _linker.findDocumentTypeRef(QNameHelper.forPretty(handle, 4));
2018 case 'Y': // _XY_ - external ref to any possible type
2019 SchemaType type = _linker.typeForSignature(handle.substring(4));
2020 if (type == null)
2021 throw new SchemaTypeLoaderException("Cannot resolve type for handle " + handle, _name, _handle, SchemaTypeLoaderException.BAD_HANDLE);
2022 return type.getRef();
2023 default:
2024 throw new SchemaTypeLoaderException("Cannot resolve handle " + handle, _name, _handle, SchemaTypeLoaderException.BAD_HANDLE);
2025 }
2026 }
2027
2028 void writeHandle(SchemaComponent comp)
2029 {
2030 if (comp == null || comp.getTypeSystem() == getTypeSystem())
2031 {
2032 writeString(_localHandles.handleForComponent(comp));
2033 return;
2034 }
2035
2036 switch (comp.getComponentType())
2037 {
2038 case SchemaComponent.ATTRIBUTE:
2039 writeString("_XA_" + QNameHelper.pretty(comp.getName()));
2040 return;
2041 case SchemaComponent.MODEL_GROUP:
2042 writeString("_XM_" + QNameHelper.pretty(comp.getName()));
2043 return;
2044 case SchemaComponent.ATTRIBUTE_GROUP:
2045 writeString("_XN_" + QNameHelper.pretty(comp.getName()));
2046 return;
2047 case SchemaComponent.ELEMENT:
2048 writeString("_XE_" + QNameHelper.pretty(comp.getName()));
2049 return;
2050 case SchemaComponent.IDENTITY_CONSTRAINT:
2051 writeString("_XD_" + QNameHelper.pretty(comp.getName()));
2052 return;
2053 case SchemaComponent.TYPE:
2054 SchemaType type = (SchemaType)comp;
2055 if (type.isBuiltinType())
2056 {
2057 writeString("_BI_" + type.getName().getLocalPart());
2058 return;
2059 }
2060
2061 // fix for CR120759 - added output of types _XR_ & _XS_
2062 // when an attribute (_XR_) or element (_XS_) declaration
2063 // uses ref to refer to an attribute or element in another
2064 // schema and the type of that attribute or element
2065 // is an anonymous (local) type
2066 // kkrouse 02/1/2005: _XR_ and _XS_ refs are replaced by _XY_
2067 if (type.getName() != null)
2068 {
2069 writeString("_XT_" + QNameHelper.pretty(type.getName()));
2070 }
2071 else if (type.isDocumentType())
2072 {
2073 // Substitution groups will create document types that
2074 // extend from other document types, possibly in
2075 // different jars
2076 writeString("_XO_" + QNameHelper.pretty(type.getDocumentElementName()));
2077 }
2078 else
2079 {
2080 // fix for XMLBEANS-105:
2081 // save out the external type reference using the type's signature.
2082 writeString("_XY_" + type.toString());
2083 }
2084
2085 return;
2086
2087 default:
2088 assert(false);
2089 throw new SchemaTypeLoaderException("Cannot write handle for component " + comp, _name, _handle, SchemaTypeLoaderException.BAD_HANDLE);
2090 }
2091 }
2092
2093 SchemaType.Ref readTypeRef()
2094 {
2095 return (SchemaType.Ref)readHandle();
2096 }
2097
2098 void writeType(SchemaType type)
2099 {
2100 writeHandle(type);
2101 }
2102
2103 Map readQNameRefMap()
2104 {
2105 Map result = new HashMap();
2106 int size = readShort();
2107 for (int i = 0; i < size; i++)
2108 {
2109 QName name = readQName();
2110 SchemaComponent.Ref obj = readHandle();
2111 result.put(name, obj);
2112 }
2113 return result;
2114 }
2115
2116 List readQNameRefMapAsList(List names)
2117 {
2118 int size = readShort();
2119 List result = new ArrayList(size);
2120 for (int i = 0; i < size; i++)
2121 {
2122 QName name = readQName();
2123 SchemaComponent.Ref obj = readHandle();
2124 result.add(obj);
2125 names.add(name);
2126 }
2127 return result;
2128 }
2129
2130 void writeQNameMap(SchemaComponent[] components)
2131 {
2132 writeShort(components.length);
2133 for (int i = 0; i < components.length; i++)
2134 {
2135 writeQName(components[i].getName());
2136 writeHandle(components[i]);
2137 }
2138 }
2139
2140 void writeDocumentTypeMap(SchemaType[] doctypes)
2141 {
2142 writeShort(doctypes.length);
2143 for (int i = 0; i < doctypes.length; i++)
2144 {
2145 writeQName(doctypes[i].getDocumentElementName());
2146 writeHandle(doctypes[i]);
2147 }
2148 }
2149
2150 void writeAttributeTypeMap(SchemaType[] attrtypes)
2151 {
2152 writeShort(attrtypes.length);
2153 for (int i = 0; i < attrtypes.length; i++)
2154 {
2155 writeQName(attrtypes[i].getAttributeTypeAttributeName());
2156 writeHandle(attrtypes[i]);
2157 }
2158 }
2159
2160 SchemaType.Ref[] readTypeRefArray()
2161 {
2162 int size = readShort();
2163 SchemaType.Ref[] result = new SchemaType.Ref[size];
2164 for (int i = 0; i < size; i++)
2165 {
2166 result[i] = readTypeRef();
2167 }
2168 return result;
2169 }
2170
2171 void writeTypeArray(SchemaType[] array)
2172 {
2173 writeShort(array.length);
2174 for (int i = 0; i < array.length; i++)
2175 {
2176 writeHandle(array[i]);
2177 }
2178 }
2179
2180 Map readClassnameRefMap()
2181 {
2182 Map result = new HashMap();
2183 int size = readShort();
2184 for (int i = 0; i < size; i++)
2185 {
2186 String name = readString();
2187 SchemaComponent.Ref obj = readHandle();
2188 result.put(name, obj);
2189 }
2190 return result;
2191 }
2192
2193 void writeClassnameMap(Map typesByClass)
2194 {
2195 writeShort(typesByClass.size());
2196 for (Iterator i = typesByClass.keySet().iterator(); i.hasNext(); )
2197 {
2198 String className = (String)i.next();
2199 writeString(className);
2200 writeHandle(((SchemaType.Ref)typesByClass.get(className)).get());
2201 }
2202 }
2203
2204 Set readNamespaces()
2205 {
2206 Set result = new HashSet();
2207 int size = readShort();
2208 for (int i = 0; i < size; i++)
2209 {
2210 String ns = readString();
2211 result.add(ns);
2212 }
2213 return result;
2214 }
2215
2216 void writeNamespaces(Set namespaces)
2217 {
2218 writeShort(namespaces.size());
2219 for (Iterator i = namespaces.iterator(); i.hasNext(); )
2220 {
2221 String ns = (String)i.next();
2222 writeString(ns);
2223 }
2224 }
2225
2226 OutputStream getSaverStream(String name)
2227 {
2228 try
2229 {
2230 return _filer.createBinaryFile(name);
2231 }
2232 catch (IOException e)
2233 {
2234 throw new SchemaTypeLoaderException(e.getMessage(), _name, _handle, SchemaTypeLoaderException.IO_EXCEPTION);
2235 }
2236 }
2237
2238 InputStream getLoaderStream(String resourcename)
2239 {
2240 return _resourceLoader.getResourceAsStream(resourcename);
2241 }
2242
2243 void checkContainerNotNull(SchemaContainer container, QName name)
2244 {
2245 if (container == null)
2246 {
2247 throw new LinkageError("Loading of resource " + _name + '.' + _handle +
2248 "failed, information from " + _name + ".index.xsb is " +
2249 " out of sync (or conflicting index files found)");
2250 }
2251 }
2252
2253 /**
2254 * Finishes loading an element after the header has already been loaded.
2255 */
2256 public SchemaGlobalElement finishLoadingElement()
2257 {
2258 String handle = null;
2259 try
2260 {
2261 int particleType = readShort();
2262 if (particleType != SchemaParticle.ELEMENT)
2263 throw new SchemaTypeLoaderException("Wrong particle type ", _name, _handle, SchemaTypeLoaderException.BAD_PARTICLE_TYPE);
2264 int particleFlags = readShort();
2265 BigInteger minOccurs = readBigInteger();
2266 BigInteger maxOccurs = readBigInteger();
2267 QNameSet transitionRules = readQNameSet();
2268 QName name = readQName();
2269 SchemaContainer container = getContainer(name.getNamespaceURI());
2270 checkContainerNotNull(container, name);
2271 SchemaGlobalElementImpl impl = new SchemaGlobalElementImpl(container);
2272 impl.setParticleType(particleType);
2273 impl.setMinOccurs(minOccurs);
2274 impl.setMaxOccurs(maxOccurs);
2275 impl.setTransitionRules(transitionRules,
2276 (particleFlags & FLAG_PART_SKIPPABLE) != 0);
2277 impl.setNameAndTypeRef(name, readTypeRef());
2278 impl.setDefault(readString(), (particleFlags & FLAG_PART_FIXED) != 0, null);
2279 if (atLeast(2, 16, 0))
2280 impl.setDefaultValue(readXmlValueObject());
2281 impl.setNillable((particleFlags & FLAG_PART_NILLABLE) != 0);
2282 impl.setBlock((particleFlags & FLAG_PART_BLOCKEXT) != 0,
2283 (particleFlags & FLAG_PART_BLOCKREST) != 0,
2284 (particleFlags & FLAG_PART_BLOCKSUBST) != 0);
2285 impl.setWsdlArrayType(readSOAPArrayType());
2286 impl.setAbstract((particleFlags & FLAG_PART_ABSTRACT) != 0);
2287 impl.setAnnotation(readAnnotation(container));
2288 impl.setFinal(
2289