src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/internalizer/SCDBasedBindingSet.java

changeset 286
f50545b5e2f1
child 368
0989ad8c0860
equal deleted inserted replaced
284:88b85470e72c 286:f50545b5e2f1
1 /*
2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.tools.internal.xjc.reader.internalizer;
27
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.Iterator;
31 import java.util.List;
32
33 import javax.xml.bind.JAXBException;
34 import javax.xml.bind.UnmarshallerHandler;
35 import javax.xml.validation.ValidatorHandler;
36
37 import com.sun.istack.internal.NotNull;
38 import com.sun.istack.internal.SAXParseException2;
39 import com.sun.tools.internal.xjc.ErrorReceiver;
40 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIDeclaration;
41 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BindInfo;
42 import com.sun.tools.internal.xjc.util.ForkContentHandler;
43 import com.sun.tools.internal.xjc.util.DOMUtils;
44 import com.sun.xml.internal.xsom.SCD;
45 import com.sun.xml.internal.xsom.XSAnnotation;
46 import com.sun.xml.internal.xsom.XSComponent;
47 import com.sun.xml.internal.xsom.XSSchemaSet;
48 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl;
49
50 import org.w3c.dom.Element;
51 import org.xml.sax.SAXException;
52 import org.xml.sax.SAXParseException;
53
54 /**
55 * Set of binding nodes that have target nodes specified via SCD.
56 *
57 * This is parsed during {@link Internalizer} works on the tree,
58 * but applying this has to wait for {@link XSSchemaSet} to be parsed.
59 *
60 * @author Kohsuke Kawaguchi
61 * @see SCD
62 */
63 public final class SCDBasedBindingSet {
64
65 /**
66 * Represents the target schema component of the
67 * customization identified by SCD.
68 *
69 * @author Kohsuke Kawaguchi
70 */
71 final class Target {
72 /**
73 * SCDs can be specified via multiple steps, like:
74 *
75 * <xmp>
76 * <bindings scd="foo/bar">
77 * <bindings scd="zot/xyz">
78 * </xmp>
79 *
80 * This field and {@link #nextSibling} form a single-linked list that
81 * represent the children that shall be evaluated within this target.
82 * Think of it as {@code List<Target>}.
83 */
84 private Target firstChild;
85 private final Target nextSibling;
86
87 /**
88 * Compiled SCD.
89 */
90 private final @NotNull SCD scd;
91
92 /**
93 * The element on which SCD was found.
94 */
95 private final @NotNull Element src;
96
97 /**
98 * Bindings that apply to this SCD.
99 */
100 private final List<Element> bindings = new ArrayList<Element>();
101
102 private Target(Target parent, Element src, SCD scd) {
103 if(parent==null) {
104 this.nextSibling = topLevel;
105 topLevel = this;
106 } else {
107 this.nextSibling = parent.firstChild;
108 parent.firstChild = this;
109 }
110 this.src = src;
111 this.scd = scd;
112 }
113
114 /**
115 * Adds a new binding declaration to be associated to the schema component
116 * identified by {@link #scd}.
117 */
118 void addBinidng(Element binding) {
119 bindings.add(binding);
120 }
121
122 /**
123 * Applies bindings to the schema component for this and its siblings.
124 */
125 private void applyAll(Collection<? extends XSComponent> contextNode) {
126 for( Target self=this; self!=null; self=self.nextSibling )
127 self.apply(contextNode);
128 }
129
130 /**
131 * Applies bindings to the schema component for just this node.
132 */
133 private void apply(Collection<? extends XSComponent> contextNode) {
134 // apply the SCD...
135 Collection<XSComponent> childNodes = scd.select(contextNode);
136 if(childNodes.isEmpty()) {
137 // no node matched
138 if(src.getAttributeNode("if-exists")!=null) {
139 // if this attribute exists, it's not an error if SCD didn't match.
140 return;
141 }
142
143 reportError( src, Messages.format(Messages.ERR_SCD_EVALUATED_EMPTY,scd) );
144 return;
145 }
146
147 if(firstChild!=null)
148 firstChild.applyAll(childNodes);
149
150 if(!bindings.isEmpty()) {
151 // error to match more than one components
152 Iterator<XSComponent> itr = childNodes.iterator();
153 XSComponent target = itr.next();
154 if(itr.hasNext()) {
155 reportError( src, Messages.format(Messages.ERR_SCD_MATCHED_MULTIPLE_NODES,scd,childNodes.size()) );
156 errorReceiver.error( target.getLocator(), Messages.format(Messages.ERR_SCD_MATCHED_MULTIPLE_NODES_FIRST) );
157 errorReceiver.error( itr.next().getLocator(), Messages.format(Messages.ERR_SCD_MATCHED_MULTIPLE_NODES_SECOND) );
158 }
159
160 // apply bindings to the target
161 for (Element binding : bindings) {
162 for (Element item : DOMUtils.getChildElements(binding)) {
163 String localName = item.getLocalName();
164
165 if ("bindings".equals(localName))
166 continue; // this should be already in Target.bindings of some SpecVersion.
167
168 try {
169 new DOMForestScanner(forest).scan(item,loader);
170 BIDeclaration decl = (BIDeclaration)unmarshaller.getResult();
171
172 // add this binding to the target
173 XSAnnotation ann = target.getAnnotation(true);
174 BindInfo bi = (BindInfo)ann.getAnnotation();
175 if(bi==null) {
176 bi = new BindInfo();
177 ann.setAnnotation(bi);
178 }
179 bi.addDecl(decl);
180 } catch (SAXException e) {
181 // the error should have already been reported.
182 } catch (JAXBException e) {
183 // if validation didn't fail, then unmarshalling can't go wrong
184 throw new AssertionError(e);
185 }
186 }
187 }
188 }
189 }
190 }
191
192 private Target topLevel;
193
194 /**
195 * The forest where binding elements came from. Needed to report line numbers for errors.
196 */
197 private final DOMForest forest;
198
199
200 // variables used only during the apply method
201 //
202 private ErrorReceiver errorReceiver;
203 private UnmarshallerHandler unmarshaller;
204 private ForkContentHandler loader; // unmarshaller+validator
205
206 SCDBasedBindingSet(DOMForest forest) {
207 this.forest = forest;
208 }
209
210 Target createNewTarget(Target parent, Element src, SCD scd) {
211 return new Target(parent,src,scd);
212 }
213
214 /**
215 * Applies the additional binding customizations.
216 */
217 public void apply(XSSchemaSet schema, ErrorReceiver errorReceiver) {
218 if(topLevel!=null) {
219 this.errorReceiver = errorReceiver;
220 UnmarshallerImpl u = BindInfo.getJAXBContext().createUnmarshaller();
221 this.unmarshaller = u.getUnmarshallerHandler();
222 ValidatorHandler v = BindInfo.bindingFileSchema.newValidator();
223 v.setErrorHandler(errorReceiver);
224 loader = new ForkContentHandler(v,unmarshaller);
225
226 topLevel.applyAll(schema.getSchemas());
227
228 this.loader = null;
229 this.unmarshaller = null;
230 this.errorReceiver = null;
231 }
232 }
233
234 private void reportError( Element errorSource, String formattedMsg ) {
235 reportError( errorSource, formattedMsg, null );
236 }
237
238 private void reportError( Element errorSource,
239 String formattedMsg, Exception nestedException ) {
240
241 SAXParseException e = new SAXParseException2( formattedMsg,
242 forest.locatorTable.getStartLocation(errorSource),
243 nestedException );
244 errorReceiver.error(e);
245 }
246 }

mercurial