Thu, 12 Oct 2017 19:44:07 +0800
merge
1 /*
2 * Copyright (c) 1997, 2010, 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.ws.policy.sourcemodel;
28 import com.sun.xml.internal.ws.policy.privateutil.LocalizationMessages;
29 import com.sun.xml.internal.ws.policy.privateutil.PolicyLogger;
30 import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils;
31 import com.sun.xml.internal.ws.policy.sourcemodel.wspolicy.XmlToken;
33 import java.util.Collection;
34 import java.util.Collections;
35 import java.util.Iterator;
36 import java.util.LinkedList;
38 /**
39 * The general representation of a single node within a {@link com.sun.xml.internal.ws.policy.sourcemodel.PolicySourceModel} instance.
40 * The model node is created via factory methods of the {@link com.sun.xml.internal.ws.policy.sourcemodel.PolicySourceModel} instance.
41 * It may also hold {@link com.sun.xml.internal.ws.policy.sourcemodel.AssertionData} instance in case its type is {@code ModelNode.Type.ASSERTION}.
42 *
43 * @author Marek Potociar
44 */
45 public final class ModelNode implements Iterable<ModelNode>, Cloneable {
46 private static final PolicyLogger LOGGER = PolicyLogger.getLogger(ModelNode.class);
48 /**
49 * Policy source model node type enumeration
50 */
51 public static enum Type {
52 POLICY(XmlToken.Policy),
53 ALL(XmlToken.All),
54 EXACTLY_ONE(XmlToken.ExactlyOne),
55 POLICY_REFERENCE(XmlToken.PolicyReference),
56 ASSERTION(XmlToken.UNKNOWN),
57 ASSERTION_PARAMETER_NODE(XmlToken.UNKNOWN);
59 private XmlToken token;
61 Type(XmlToken token) {
62 this.token = token;
63 }
65 public XmlToken getXmlToken() {
66 return token;
67 }
69 /**
70 * Method checks the PSM state machine if the creation of new child of given type is plausible for a node element
71 * with type set to this type instance.
72 *
73 * @param childType The type.
74 * @return True if the type is supported, false otherwise
75 */
76 private boolean isChildTypeSupported(final Type childType) {
77 switch (this) {
78 case POLICY:
79 case ALL:
80 case EXACTLY_ONE:
81 switch (childType) {
82 case ASSERTION_PARAMETER_NODE:
83 return false;
84 default:
85 return true;
86 }
87 case POLICY_REFERENCE:
88 return false;
89 case ASSERTION:
90 switch (childType) {
91 case POLICY:
92 case POLICY_REFERENCE:
93 case ASSERTION_PARAMETER_NODE:
94 return true;
95 default:
96 return false;
97 }
98 case ASSERTION_PARAMETER_NODE:
99 switch (childType) {
100 case ASSERTION_PARAMETER_NODE:
101 return true;
102 default:
103 return false;
104 }
105 default:
106 throw LOGGER.logSevereException(new IllegalStateException(
107 LocalizationMessages.WSP_0060_POLICY_ELEMENT_TYPE_UNKNOWN(this)));
108 }
109 }
110 }
112 // comon model node attributes
113 private LinkedList<ModelNode> children;
114 private Collection<ModelNode> unmodifiableViewOnContent;
115 private final ModelNode.Type type;
116 private ModelNode parentNode;
117 private PolicySourceModel parentModel;
119 // attributes used only in 'POLICY_REFERENCE' model node
120 private PolicyReferenceData referenceData;
121 private PolicySourceModel referencedModel;
123 // attibutes used only in 'ASSERTION' or 'ASSERTION_PARAMETER_NODE' model node
124 private AssertionData nodeData;
126 /**
127 * The factory method creates and initializes the POLICY model node and sets it's parent model reference to point to
128 * the model supplied as an input parameter. This method is intended to be used ONLY from {@link PolicySourceModel} during
129 * the initialization of its own internal structures.
130 *
131 * @param model policy source model to be used as a parent model of the newly created {@link ModelNode}. Must not be {@code null}
132 * @return POLICY model node with the parent model reference initialized to the model supplied as an input parameter
133 * @throws IllegalArgumentException if the {@code model} input parameter is {@code null}
134 */
135 static ModelNode createRootPolicyNode(final PolicySourceModel model) throws IllegalArgumentException {
136 if (model == null) {
137 throw LOGGER.logSevereException(new IllegalArgumentException(LocalizationMessages.WSP_0039_POLICY_SRC_MODEL_INPUT_PARAMETER_MUST_NOT_BE_NULL()));
138 }
139 return new ModelNode(ModelNode.Type.POLICY, model);
140 }
142 private ModelNode(Type type, PolicySourceModel parentModel) {
143 this.type = type;
144 this.parentModel = parentModel;
145 this.children = new LinkedList<ModelNode>();
146 this.unmodifiableViewOnContent = Collections.unmodifiableCollection(this.children);
147 }
149 private ModelNode(Type type, PolicySourceModel parentModel, AssertionData data) {
150 this(type, parentModel);
152 this.nodeData = data;
153 }
155 private ModelNode(PolicySourceModel parentModel, PolicyReferenceData data) {
156 this(Type.POLICY_REFERENCE, parentModel);
158 this.referenceData = data;
159 }
161 private void checkCreateChildOperationSupportForType(final Type type) throws UnsupportedOperationException {
162 if (!this.type.isChildTypeSupported(type)) {
163 throw LOGGER.logSevereException(new UnsupportedOperationException(LocalizationMessages.WSP_0073_CREATE_CHILD_NODE_OPERATION_NOT_SUPPORTED(type, this.type)));
164 }
165 }
167 /**
168 * Factory method that creates new policy source model node as specified by a factory method name and input parameters.
169 * Each node is created with respect to its enclosing policy source model.
170 *
171 * @return A new Policy node.
172 */
173 public ModelNode createChildPolicyNode() {
174 checkCreateChildOperationSupportForType(Type.POLICY);
176 final ModelNode node = new ModelNode(ModelNode.Type.POLICY, parentModel);
177 this.addChild(node);
179 return node;
180 }
182 /**
183 * Factory method that creates new policy source model node as specified by a factory method name and input parameters.
184 * Each node is created with respect to its enclosing policy source model.
185 *
186 * @return A new All node.
187 */
188 public ModelNode createChildAllNode() {
189 checkCreateChildOperationSupportForType(Type.ALL);
191 final ModelNode node = new ModelNode(ModelNode.Type.ALL, parentModel);
192 this.addChild(node);
194 return node;
195 }
197 /**
198 * Factory method that creates new policy source model node as specified by a factory method name and input parameters.
199 * Each node is created with respect to its enclosing policy source model.
200 *
201 * @return A new ExactlyOne node.
202 */
203 public ModelNode createChildExactlyOneNode() {
204 checkCreateChildOperationSupportForType(Type.EXACTLY_ONE);
206 final ModelNode node = new ModelNode(ModelNode.Type.EXACTLY_ONE, parentModel);
207 this.addChild(node);
209 return node;
210 }
212 /**
213 * Factory method that creates new policy source model node as specified by a factory method name and input parameters.
214 * Each node is created with respect to its enclosing policy source model.
215 *
216 * @return A new policy assertion node.
217 */
218 public ModelNode createChildAssertionNode() {
219 checkCreateChildOperationSupportForType(Type.ASSERTION);
221 final ModelNode node = new ModelNode(ModelNode.Type.ASSERTION, parentModel);
222 this.addChild(node);
224 return node;
225 }
227 /**
228 * Factory method that creates new policy source model node as specified by a factory method name and input parameters.
229 * Each node is created with respect to its enclosing policy source model.
230 *
231 * @param nodeData The policy assertion data.
232 * @return A new policy assertion node.
233 */
234 public ModelNode createChildAssertionNode(final AssertionData nodeData) {
235 checkCreateChildOperationSupportForType(Type.ASSERTION);
237 final ModelNode node = new ModelNode(Type.ASSERTION, parentModel, nodeData);
238 this.addChild(node);
240 return node;
241 }
243 /**
244 * Factory method that creates new policy source model node as specified by a factory method name and input parameters.
245 * Each node is created with respect to its enclosing policy source model.
246 *
247 * @return A new assertion parameter node.
248 */
249 public ModelNode createChildAssertionParameterNode() {
250 checkCreateChildOperationSupportForType(Type.ASSERTION_PARAMETER_NODE);
252 final ModelNode node = new ModelNode(ModelNode.Type.ASSERTION_PARAMETER_NODE, parentModel);
253 this.addChild(node);
255 return node;
256 }
258 /**
259 * Factory method that creates new policy source model node as specified by a factory method name and input parameters.
260 * Each node is created with respect to its enclosing policy source model.
261 *
262 * @param nodeData The assertion parameter data.
263 * @return A new assertion parameter node.
264 */
265 ModelNode createChildAssertionParameterNode(final AssertionData nodeData) {
266 checkCreateChildOperationSupportForType(Type.ASSERTION_PARAMETER_NODE);
268 final ModelNode node = new ModelNode(Type.ASSERTION_PARAMETER_NODE, parentModel, nodeData);
269 this.addChild(node);
271 return node;
272 }
274 /**
275 * Factory method that creates new policy source model node as specified by a factory method name and input parameters.
276 * Each node is created with respect to its enclosing policy source model.
277 *
278 * @param referenceData The PolicyReference data.
279 * @return A new PolicyReference node.
280 */
281 ModelNode createChildPolicyReferenceNode(final PolicyReferenceData referenceData) {
282 checkCreateChildOperationSupportForType(Type.POLICY_REFERENCE);
284 final ModelNode node = new ModelNode(parentModel, referenceData);
285 this.parentModel.addNewPolicyReference(node);
286 this.addChild(node);
288 return node;
289 }
291 Collection<ModelNode> getChildren() {
292 return unmodifiableViewOnContent;
293 }
295 /**
296 * Sets the parent model reference on the node and its children. The method may be invoked only on the root node
297 * of the policy source model (or - in general - on a model node that dose not reference a parent node). Otherwise an
298 * exception is thrown.
299 *
300 * @param model new parent policy source model to be set.
301 * @throws IllegalAccessException in case this node references a parent node (i.e. is not a root node of the model).
302 */
303 void setParentModel(final PolicySourceModel model) throws IllegalAccessException {
304 if (parentNode != null) {
305 throw LOGGER.logSevereException(new IllegalAccessException(LocalizationMessages.WSP_0049_PARENT_MODEL_CAN_NOT_BE_CHANGED()));
306 }
308 this.updateParentModelReference(model);
309 }
311 /**
312 * The method updates the parentModel reference on current model node instance and all of it's children
313 *
314 * @param model new policy source model reference.
315 */
316 private void updateParentModelReference(final PolicySourceModel model) {
317 this.parentModel = model;
319 for (ModelNode child : children) {
320 child.updateParentModelReference(model);
321 }
322 }
324 /**
325 * Returns the parent policy source model that contains this model node.
326 *
327 * @return the parent policy source model
328 */
329 public PolicySourceModel getParentModel() {
330 return parentModel;
331 }
333 /**
334 * Returns the type of this policy source model node.
335 *
336 * @return actual type of this policy source model node
337 */
338 public ModelNode.Type getType() {
339 return type;
340 }
342 /**
343 * Returns the parent referenced by this policy source model node.
344 *
345 * @return current parent of this policy source model node or {@code null} if the node does not have a parent currently.
346 */
347 public ModelNode getParentNode() {
348 return parentNode;
349 }
351 /**
352 * Returns the data for this policy source model node (if any). The model node data are expected to be not {@code null} only in
353 * case the type of this node is ASSERTION or ASSERTION_PARAMETER_NODE.
354 *
355 * @return the data of this policy source model node or {@code null} if the node does not have any data associated to it
356 * attached.
357 */
358 public AssertionData getNodeData() {
359 return nodeData;
360 }
362 /**
363 * Returns the policy reference data for this policy source model node. The policy reference data are expected to be not {@code null} only in
364 * case the type of this node is POLICY_REFERENCE.
365 *
366 * @return the policy reference data for this policy source model node or {@code null} if the node does not have any policy reference data
367 * attached.
368 */
369 PolicyReferenceData getPolicyReferenceData() {
370 return referenceData;
371 }
373 /**
374 * The method may be used to set or replace assertion data set for this node. If there are assertion data set already,
375 * those are replaced by a new reference and eventualy returned from the method.
376 * <p/>
377 * This method is supported only in case this model node instance's type is {@code ASSERTION} or {@code ASSERTION_PARAMETER_NODE}.
378 * If used from other node types, an exception is thrown.
379 *
380 * @param newData new assertion data to be set.
381 * @return old and replaced assertion data if any or {@code null} otherwise.
382 *
383 * @throws UnsupportedOperationException in case this method is called on nodes of type other than {@code ASSERTION}
384 * or {@code ASSERTION_PARAMETER_NODE}
385 */
386 public AssertionData setOrReplaceNodeData(final AssertionData newData) {
387 if (!isDomainSpecific()) {
388 throw LOGGER.logSevereException(new UnsupportedOperationException(LocalizationMessages.WSP_0051_OPERATION_NOT_SUPPORTED_FOR_THIS_BUT_ASSERTION_RELATED_NODE_TYPE(type)));
389 }
391 final AssertionData oldData = this.nodeData;
392 this.nodeData = newData;
394 return oldData;
395 }
397 /**
398 * The method specifies whether the model node instance represents assertion related node, it means whether its type
399 * is 'ASSERTION' or 'ASSERTION_PARAMETER_NODE'. This is, for example, the way to determine whether the node supports
400 * setting a {@link AssertionData} object via {@link #setOrReplaceNodeData(AssertionData)} method or not.
401 *
402 * @return {@code true} or {@code false} according to whether the node instance represents assertion related node or not.
403 */
404 boolean isDomainSpecific() {
405 return type == Type.ASSERTION || type == Type.ASSERTION_PARAMETER_NODE;
406 }
408 /**
409 * Appends the specified child node to the end of the children list of this node and sets it's parent to reference
410 * this node.
411 *
412 * @param child node to be appended to the children list of this node.
413 * @return {@code true} (as per the general contract of the {@code Collection.add} method).
414 *
415 * @throws NullPointerException if the specified node is {@code null}.
416 * @throws IllegalArgumentException if child has a parent node set already to point to some node
417 */
418 private boolean addChild(final ModelNode child) {
419 children.add(child);
420 child.parentNode = this;
422 return true;
423 }
425 void setReferencedModel(final PolicySourceModel model) {
426 if (this.type != Type.POLICY_REFERENCE) {
427 throw LOGGER.logSevereException(new UnsupportedOperationException(LocalizationMessages.WSP_0050_OPERATION_NOT_SUPPORTED_FOR_THIS_BUT_POLICY_REFERENCE_NODE_TYPE(type)));
428 }
430 referencedModel = model;
431 }
433 PolicySourceModel getReferencedModel() {
434 return referencedModel;
435 }
437 /**
438 * Returns the number of child policy source model nodes. If this model node contains
439 * more than {@code Integer.MAX_VALUE} children, returns {@code Integer.MAX_VALUE}.
440 *
441 * @return the number of children of this node.
442 */
443 public int childrenSize() {
444 return children.size();
445 }
447 /**
448 * Returns true if the node has at least one child node.
449 *
450 * @return true if the node has at least one child node, false otherwise.
451 */
452 public boolean hasChildren() {
453 return !children.isEmpty();
454 }
456 /**
457 * Iterates through all child nodes.
458 *
459 * @return An iterator for the child nodes
460 */
461 public Iterator<ModelNode> iterator() {
462 return children.iterator();
463 }
465 /**
466 * An {@code Object.equals(Object obj)} method override. Method ignores the parent source model. It means that two
467 * model nodes may be the same even if they belong to different models.
468 * <p/>
469 * If parent model comparison is desired, it must be accomplished separately. To perform that, the reference equality
470 * test is sufficient ({@code nodeA.getParentModel() == nodeB.getParentModel()}), since all model nodes are created
471 * for specific model instances.
472 */
473 @Override
474 public boolean equals(final Object obj) {
475 if (this == obj) {
476 return true;
477 }
479 if (!(obj instanceof ModelNode)) {
480 return false;
481 }
483 boolean result = true;
484 final ModelNode that = (ModelNode) obj;
486 result = result && this.type.equals(that.type);
487 // result = result && ((this.parentNode == null) ? that.parentNode == null : this.parentNode.equals(that.parentNode));
488 result = result && ((this.nodeData == null) ? that.nodeData == null : this.nodeData.equals(that.nodeData));
489 result = result && ((this.children == null) ? that.children == null : this.children.equals(that.children));
491 return result;
492 }
494 /**
495 * An {@code Object.hashCode()} method override.
496 */
497 @Override
498 public int hashCode() {
499 int result = 17;
501 result = 37 * result + this.type.hashCode();
502 result = 37 * result + ((this.parentNode == null) ? 0 : this.parentNode.hashCode());
503 result = 37 * result + ((this.nodeData == null) ? 0 : this.nodeData.hashCode());
504 result = 37 * result + this.children.hashCode();
506 return result;
507 }
509 /**
510 * Returns a string representation of the object. In general, the <code>toString</code> method
511 * returns a string that "textually represents" this object.
512 *
513 * @return a string representation of the object.
514 */
515 @Override
516 public String toString() {
517 return toString(0, new StringBuffer()).toString();
518 }
520 /**
521 * A helper method that appends indented string representation of this instance to the input string buffer.
522 *
523 * @param indentLevel indentation level to be used.
524 * @param buffer buffer to be used for appending string representation of this instance
525 * @return modified buffer containing new string representation of the instance
526 */
527 public StringBuffer toString(final int indentLevel, final StringBuffer buffer) {
528 final String indent = PolicyUtils.Text.createIndent(indentLevel);
529 final String innerIndent = PolicyUtils.Text.createIndent(indentLevel + 1);
531 buffer.append(indent).append(type).append(" {").append(PolicyUtils.Text.NEW_LINE);
532 if (type == Type.ASSERTION) {
533 if (nodeData == null) {
534 buffer.append(innerIndent).append("no assertion data set");
535 } else {
536 nodeData.toString(indentLevel + 1, buffer);
537 }
538 buffer.append(PolicyUtils.Text.NEW_LINE);
539 } else if (type == Type.POLICY_REFERENCE) {
540 if (referenceData == null) {
541 buffer.append(innerIndent).append("no policy reference data set");
542 } else {
543 referenceData.toString(indentLevel + 1, buffer);
544 }
545 buffer.append(PolicyUtils.Text.NEW_LINE);
546 } else if (type == Type.ASSERTION_PARAMETER_NODE) {
547 if (nodeData == null) {
548 buffer.append(innerIndent).append("no parameter data set");
549 }
550 else {
551 nodeData.toString(indentLevel + 1, buffer);
552 }
553 buffer.append(PolicyUtils.Text.NEW_LINE);
554 }
556 if (children.size() > 0) {
557 for (ModelNode child : children) {
558 child.toString(indentLevel + 1, buffer).append(PolicyUtils.Text.NEW_LINE);
559 }
560 } else {
561 buffer.append(innerIndent).append("no child nodes").append(PolicyUtils.Text.NEW_LINE);
562 }
564 buffer.append(indent).append('}');
565 return buffer;
566 }
568 @Override
569 protected ModelNode clone() throws CloneNotSupportedException {
570 final ModelNode clone = (ModelNode) super.clone();
572 if (this.nodeData != null) {
573 clone.nodeData = this.nodeData.clone();
574 }
576 // no need to clone PolicyReferenceData, since those are immutable
578 if (this.referencedModel != null) {
579 clone.referencedModel = this.referencedModel.clone();
580 }
583 clone.children = new LinkedList<ModelNode>();
584 clone.unmodifiableViewOnContent = Collections.unmodifiableCollection(clone.children);
586 for (ModelNode thisChild : this.children) {
587 clone.addChild(thisChild.clone());
588 }
590 return clone;
591 }
593 PolicyReferenceData getReferenceData() {
594 return referenceData;
595 }
596 }