1 /*
2 * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package com.sun.tools.internal.xjc.reader.xmlschema.bindinfo;
27
28 import java.util.Collections;
29
30 import javax.xml.bind.JAXBContext;
31 import javax.xml.bind.JAXBException;
32 import javax.xml.bind.Unmarshaller;
33 import javax.xml.bind.UnmarshallerHandler;
34 import javax.xml.bind.helpers.DefaultValidationEventHandler;
35 import javax.xml.validation.ValidatorHandler;
36
37 import com.sun.tools.internal.xjc.Options;
38 import com.sun.tools.internal.xjc.SchemaCache;
39 import com.sun.tools.internal.xjc.reader.Const;
40 import com.sun.xml.internal.bind.api.TypeReference;
41 import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl;
42 import com.sun.xml.internal.xsom.parser.AnnotationContext;
43 import com.sun.xml.internal.xsom.parser.AnnotationParser;
44 import com.sun.xml.internal.xsom.parser.AnnotationParserFactory;
45
46 import org.xml.sax.Attributes;
47 import org.xml.sax.ContentHandler;
48 import org.xml.sax.EntityResolver;
49 import org.xml.sax.ErrorHandler;
50 import org.xml.sax.SAXException;
51 import org.xml.sax.helpers.XMLFilterImpl;
52
53 /**
54 * Implementation of XSOM {@link AnnotationParserFactory} that
55 * parses JAXB customization declarations.
56 *
57 * @author
58 * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
59 */
60 public class AnnotationParserFactoryImpl implements AnnotationParserFactory {
61 public AnnotationParserFactoryImpl(Options opts) {
62 this.options=opts;
63 }
64
65 private final Options options;
66 /**
67 * Lazily created validator, so that the schema for binding won't be
68 * prepared unless absolutely necessary.
69 */
70 private ValidatorHandler validator;
71
72 /**
73 * Lazily parsed schema for the binding file.
74 */
75 private static final SchemaCache bindingFileSchema = new SchemaCache(AnnotationParserFactoryImpl.class.getResource("binding.xsd"));
76
77 /**
78 * Lazily prepared {@link JAXBContext}.
79 */
80 private static JAXBContextImpl customizationContext;
81
82 private static JAXBContextImpl getJAXBContext() {
83 synchronized(AnnotationParserFactoryImpl.class) {
84 try {
85 if(customizationContext==null)
86 customizationContext = new JAXBContextImpl(
87 new Class[] {
88 BindInfo.class, // for xs:annotation
89 BIClass.class,
90 BIConversion.User.class,
91 BIConversion.UserAdapter.class,
92 BIDom.class,
93 BIXDom.class,
94 BIEnum.class,
95 BIEnumMember.class,
96 BIGlobalBinding.class,
97 BIProperty.class,
98 BISchemaBinding.class
99 }, Collections.<TypeReference>emptyList(), null, false);
100 return customizationContext;
101 } catch (JAXBException e) {
102 throw new AssertionError(e);
103 }
104 }
105 }
106
107 public AnnotationParser create() {
108 return new AnnotationParser() {
109 private Unmarshaller u = getJAXBContext().createUnmarshaller();
110
111 private UnmarshallerHandler handler;
112
113 public ContentHandler getContentHandler(
114 AnnotationContext context, String parentElementName,
115 final ErrorHandler errorHandler, EntityResolver entityResolver ) {
116
117 // return a ContentHandler that validates the customization and also
118 // parses them into the internal structure.
119 if(handler!=null)
120 // interface contract violation.
121 // this method will be called only once.
122 throw new AssertionError();
123
124 if(options.debugMode)
125 try {
126 u.setEventHandler(new DefaultValidationEventHandler());
127 } catch (JAXBException e) {
128 throw new AssertionError(e); // ridiculous!
129 }
130
131 handler = u.getUnmarshallerHandler();
132
133 // configure so that the validator will receive events for JAXB islands
134 return new ForkingFilter(handler) {
135 @Override
136 public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
137 super.startElement(uri, localName, qName, atts);
138 if((uri.equals(Const.JAXB_NSURI) || uri.equals(Const.XJC_EXTENSION_URI))
139 && getSideHandler()==null) {
140 // set up validator
141 if(validator==null)
142 validator = bindingFileSchema.newValidator();
143 validator.setErrorHandler(errorHandler);
144 startForking(uri,localName,qName,atts,new ValidatorProtecter(validator));
145 }
146 }
147 };
148 }
149
150 public Object getResult( Object existing ) {
151 if(handler==null)
152 // interface contract violation.
153 // the getContentHandler method must have been called.
154 throw new AssertionError();
155
156 try {
157 BindInfo result = (BindInfo)handler.getResult();
158
159 if(existing!=null) {
160 BindInfo bie = (BindInfo)existing;
161 bie.absorb(result);
162 return bie;
163 } else {
164 if(!result.isPointless())
165 return result; // just annotation. no meaningful customization
166 else
167 return null;
168 }
169 } catch (JAXBException e) {
170 throw new AssertionError(e);
171 }
172 }
173 };
174 }
175
176 private static final class ValidatorProtecter extends XMLFilterImpl {
177 public ValidatorProtecter(ContentHandler h) {
178 setContentHandler(h);
179 }
180
181 public void startPrefixMapping(String prefix, String uri) throws SAXException {
182 // work around a bug in the validator implementation in Tiger
183 super.startPrefixMapping(prefix.intern(),uri);
184 }
185 }
186 }