Thu, 12 Oct 2017 19:44:07 +0800
merge
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 */
26 package com.sun.xml.internal.bind.v2.schemagen;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.List;
32 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.ContentModelContainer;
33 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.Particle;
34 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.TypeDefParticle;
35 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.Occurs;
37 /**
38 * Normalized representation of the content model.
39 *
40 * <p>
41 * This is built from bottom up so that we can eliminate redundant constructs,
42 * and produce the most concise content model definition in XML.
43 *
44 * @author Kohsuke Kawaguchi
45 */
46 abstract class Tree {
48 /**
49 * Returns "T?" from "T".
50 *
51 * @param really
52 * if false this method becomes no-op. This is so that we can write
53 * the caller fluently.
54 */
55 Tree makeOptional(boolean really) {
56 return really?new Optional(this) :this;
57 }
59 /**
60 * Returns "T+" from "T".
61 *
62 * @param really
63 * if false this method becomes no-op. This is so that we can write
64 * the caller fluently.
65 */
66 Tree makeRepeated(boolean really) {
67 return really?new Repeated(this) :this;
68 }
70 /**
71 * Returns a group tree.
72 */
73 static Tree makeGroup(GroupKind kind, List<Tree> children ) {
74 // pointless binary operator.
75 if(children.size()==1)
76 return children.get(0);
78 // we neither have epsilon or emptySet, so can't handle children.length==0 nicely
80 // eliminated nesting groups of the same kind.
81 // this is where binary tree would have shined.
82 List<Tree> normalizedChildren = new ArrayList<Tree>(children.size());
83 for (Tree t : children) {
84 if (t instanceof Group) {
85 Group g = (Group) t;
86 if(g.kind==kind) {
87 normalizedChildren.addAll(Arrays.asList(g.children));
88 continue;
89 }
90 }
91 normalizedChildren.add(t);
92 }
94 return new Group(kind,normalizedChildren.toArray(new Tree[normalizedChildren.size()]));
95 }
97 /**
98 * Returns true if this tree accepts empty sequence.
99 */
100 abstract boolean isNullable();
102 /**
103 * Returns true if the top node of this tree can
104 * appear as a valid top-level content model in XML Schema.
105 *
106 * <p>
107 * Model groups and occurrences that have model group in it can.
108 */
109 boolean canBeTopLevel() { return false; }
111 /**
112 * Writes out the content model.
113 *
114 * Normall this runs recursively until we write out the whole content model.
115 */
116 protected abstract void write(ContentModelContainer parent, boolean isOptional, boolean repeated);
118 /**
119 * Writes inside the given complex type.
120 */
121 protected void write(TypeDefParticle ct) {
122 if(canBeTopLevel())
123 write(ct._cast(ContentModelContainer.class), false, false);
124 else
125 // need a dummy wrapper
126 new Group(GroupKind.SEQUENCE,this).write(ct);
127 }
129 /**
130 * Convenience method to write occurrence constraints.
131 */
132 protected final void writeOccurs(Occurs o, boolean isOptional, boolean repeated) {
133 if(isOptional)
134 o.minOccurs(0);
135 if(repeated)
136 o.maxOccurs("unbounded");
137 }
139 /**
140 * Represents a terminal tree node, such as element, wildcard, etc.
141 */
142 abstract static class Term extends Tree {
143 boolean isNullable() {
144 return false;
145 }
146 }
148 /**
149 * "T?"
150 */
151 private static final class Optional extends Tree {
152 private final Tree body;
154 private Optional(Tree body) {
155 this.body = body;
156 }
158 @Override
159 boolean isNullable() {
160 return true;
161 }
163 @Override
164 Tree makeOptional(boolean really) {
165 return this;
166 }
168 @Override
169 protected void write(ContentModelContainer parent, boolean isOptional, boolean repeated) {
170 body.write(parent,true,repeated);
171 }
172 }
174 /**
175 * "T+"
176 */
177 private static final class Repeated extends Tree {
178 private final Tree body;
180 private Repeated(Tree body) {
181 this.body = body;
182 }
184 @Override
185 boolean isNullable() {
186 return body.isNullable();
187 }
189 @Override
190 Tree makeRepeated(boolean really) {
191 return this;
192 }
194 @Override
195 protected void write(ContentModelContainer parent, boolean isOptional, boolean repeated) {
196 body.write(parent,isOptional,true);
197 }
198 }
200 /**
201 * "S|T", "S,T", and "S&T".
202 */
203 private static final class Group extends Tree {
204 private final GroupKind kind;
205 private final Tree[] children;
207 private Group(GroupKind kind, Tree... children) {
208 this.kind = kind;
209 this.children = children;
210 }
212 @Override
213 boolean canBeTopLevel() {
214 return true;
215 }
217 @Override
218 boolean isNullable() {
219 if(kind== GroupKind.CHOICE) {
220 for (Tree t : children) {
221 if(t.isNullable())
222 return true;
223 }
224 return false;
225 } else {
226 for (Tree t : children) {
227 if(!t.isNullable())
228 return false;
229 }
230 return true;
231 }
232 }
234 @Override
235 protected void write(ContentModelContainer parent, boolean isOptional, boolean repeated) {
236 Particle c = kind.write(parent);
237 writeOccurs(c,isOptional,repeated);
239 for (Tree child : children) {
240 child.write(c,false,false);
241 }
242 }
243 }
244 }