001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.xml.ws.policy.sourcemodel;
038:
039: import com.sun.xml.ws.policy.PolicyConstants;
040: import com.sun.xml.ws.policy.privateutil.LocalizationMessages;
041: import com.sun.xml.ws.policy.privateutil.PolicyLogger;
042: import com.sun.xml.ws.policy.privateutil.PolicyUtils;
043: import java.util.Collection;
044: import java.util.Collections;
045: import java.util.Iterator;
046: import java.util.LinkedList;
047: import javax.xml.namespace.QName;
048:
049: /**
050: * The general representation of a single node within a {@link com.sun.xml.ws.policy.sourcemodel.PolicySourceModel} instance.
051: * The model node is created via factory methods of the {@link com.sun.xml.ws.policy.sourcemodel.PolicySourceModel} instance.
052: * It may also hold {@link com.sun.xml.ws.policy.sourcemodel.AssertionData} instance in case its type is {@code ModelNode.Type.ASSERTION}.
053: *
054: * @author Marek Potociar
055: */
056: public final class ModelNode implements Iterable<ModelNode>, Cloneable {
057: private static final PolicyLogger LOGGER = PolicyLogger
058: .getLogger(ModelNode.class);
059:
060: /**
061: * Policy source model node type enumeration
062: */
063: public static enum Type {
064: POLICY(
065: new QName(PolicyConstants.POLICY_NAMESPACE_URI,
066: "Policy")), ALL(new QName(
067: PolicyConstants.POLICY_NAMESPACE_URI, "All")), EXACTLY_ONE(
068: new QName(PolicyConstants.POLICY_NAMESPACE_URI,
069: "ExactlyOne")), POLICY_REFERENCE(
070: new QName(PolicyConstants.POLICY_NAMESPACE_URI,
071: "PolicyReference")), ASSERTION(null), ASSERTION_PARAMETER_NODE(
072: null);
073:
074: private QName qName;
075:
076: Type(QName qName) {
077: this .qName = qName;
078: }
079:
080: public QName asQName() {
081: return qName;
082: }
083:
084: /**
085: * Method checks the PSM state machine if the creation of new child of given type is plausible for a node element
086: * with type set to this type instance.
087: */
088: boolean isChildTypeSupported(final Type childType) {
089: switch (this ) {
090: case POLICY:
091: case ALL:
092: case EXACTLY_ONE:
093: switch (childType) {
094: case ASSERTION_PARAMETER_NODE:
095: return false;
096: default:
097: return true;
098: }
099: case POLICY_REFERENCE:
100: return false;
101: case ASSERTION:
102: switch (childType) {
103: case POLICY:
104: case POLICY_REFERENCE:
105: case ASSERTION_PARAMETER_NODE:
106: return true;
107: default:
108: return false;
109: }
110: case ASSERTION_PARAMETER_NODE:
111: switch (childType) {
112: case ASSERTION_PARAMETER_NODE:
113: return true;
114: default:
115: return false;
116: }
117: default:
118: throw LOGGER
119: .logSevereException(new IllegalStateException(
120: LocalizationMessages
121: .WSP_0060_MODEL_NODE_TYPE_UNKNOWN(this )));
122: }
123: }
124: }
125:
126: // comon model node attributes
127: private LinkedList<ModelNode> content;
128: private Collection<ModelNode> unmodifiableViewOnContent;
129: private final ModelNode.Type type;
130: private ModelNode parentNode;
131: private PolicySourceModel parentModel;
132:
133: // attributes used only in 'POLICY_REFERENCE' model node
134: private PolicyReferenceData referenceData;
135: private PolicySourceModel referencedModel;
136:
137: // attibutes used only in 'ASSERTION' or 'ASSERTION_PARAMETER_NODE' model node
138: private AssertionData nodeData;
139:
140: /**
141: * The factory method creates and initializes the POLICY model node and sets it's parent model reference to point to
142: * the model supplied as an input parameter. This method is intended to be used ONLY from {@link PolicySourceModel} during
143: * the initialization of its own internal structures.
144: *
145: * @param model policy source model to be used as a parent model of the newly created {@link ModelNode}. Must not be {@code null}
146: * @return POLICY model node with the parent model reference initialized to the model supplied as an input parameter
147: * @throws IllegalArgumentException if the {@code model} input parameter is {@code null}
148: */
149: static ModelNode createRootPolicyNode(final PolicySourceModel model)
150: throws IllegalArgumentException {
151: if (model == null) {
152: throw LOGGER
153: .logSevereException(new IllegalArgumentException(
154: LocalizationMessages
155: .WSP_0039_POLICY_SRC_MODEL_INPUT_PARAMETER_MUST_NOT_BE_NULL()));
156: }
157: return new ModelNode(ModelNode.Type.POLICY, model);
158: }
159:
160: private ModelNode(Type type, PolicySourceModel parentModel) {
161: this .type = type;
162: this .parentModel = parentModel;
163: this .content = new LinkedList<ModelNode>();
164: this .unmodifiableViewOnContent = Collections
165: .unmodifiableCollection(this .content);
166: }
167:
168: private ModelNode(Type type, PolicySourceModel parentModel,
169: AssertionData data) {
170: this (type, parentModel);
171:
172: this .nodeData = data;
173: }
174:
175: private ModelNode(PolicySourceModel parentModel,
176: PolicyReferenceData data) {
177: this (Type.POLICY_REFERENCE, parentModel);
178:
179: this .referenceData = data;
180: }
181:
182: private void checkCreateChildOperationSupportForType(final Type type)
183: throws UnsupportedOperationException {
184: if (!this .type.isChildTypeSupported(type)) {
185: throw LOGGER
186: .logSevereException(new UnsupportedOperationException(
187: LocalizationMessages
188: .WSP_0073_CREATE_CHILD_NODE_OPERATION_NOT_SUPPORTED(
189: type, this .type)));
190: }
191: }
192:
193: /**
194: * TODO: proper java doc
195: *
196: * Factory method that creates new policy source model node as specified by a factory method name and input parameters.
197: * Each node is created with respect to its enclosing policy source model.
198: */
199: public ModelNode createChildPolicyNode() {
200: checkCreateChildOperationSupportForType(Type.POLICY);
201:
202: final ModelNode node = new ModelNode(ModelNode.Type.POLICY,
203: parentModel);
204: this .addChild(node);
205:
206: return node;
207: }
208:
209: /**
210: * TODO: proper java doc
211: *
212: * Factory method that creates new policy source model node as specified by a factory method name and input parameters.
213: * Each node is created with respect to its enclosing policy source model.
214: */
215: public ModelNode createChildAllNode() {
216: checkCreateChildOperationSupportForType(Type.ALL);
217:
218: final ModelNode node = new ModelNode(ModelNode.Type.ALL,
219: parentModel);
220: this .addChild(node);
221:
222: return node;
223: }
224:
225: /**
226: * TODO: proper java doc
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: public ModelNode createChildExactlyOneNode() {
232: checkCreateChildOperationSupportForType(Type.EXACTLY_ONE);
233:
234: final ModelNode node = new ModelNode(
235: ModelNode.Type.EXACTLY_ONE, parentModel);
236: this .addChild(node);
237:
238: return node;
239: }
240:
241: /**
242: * TODO: proper java doc
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: public ModelNode createChildAssertionNode() {
248: checkCreateChildOperationSupportForType(Type.ASSERTION);
249:
250: final ModelNode node = new ModelNode(ModelNode.Type.ASSERTION,
251: parentModel);
252: this .addChild(node);
253:
254: return node;
255: }
256:
257: /**
258: * TODO: proper java doc
259: *
260: * Factory method that creates new policy source model node as specified by a factory method name and input parameters.
261: * Each node is created with respect to its enclosing policy source model.
262: */
263: public ModelNode createChildAssertionNode(
264: final AssertionData nodeData) {
265: checkCreateChildOperationSupportForType(Type.ASSERTION);
266:
267: final ModelNode node = new ModelNode(Type.ASSERTION,
268: parentModel, nodeData);
269: this .addChild(node);
270:
271: return node;
272: }
273:
274: /**
275: * TODO: proper java doc
276: *
277: * Factory method that creates new policy source model node as specified by a factory method name and input parameters.
278: * Each node is created with respect to its enclosing policy source model.
279: */
280: public ModelNode createChildAssertionParameterNode() {
281: checkCreateChildOperationSupportForType(Type.ASSERTION_PARAMETER_NODE);
282:
283: final ModelNode node = new ModelNode(
284: ModelNode.Type.ASSERTION_PARAMETER_NODE, parentModel);
285: this .addChild(node);
286:
287: return node;
288: }
289:
290: /**
291: * TODO: proper java doc
292: *
293: * Factory method that creates new policy source model node as specified by a factory method name and input parameters.
294: * Each node is created with respect to its enclosing policy source model.
295: */
296: public ModelNode createChildAssertionParameterNode(
297: final AssertionData nodeData) {
298: checkCreateChildOperationSupportForType(Type.ASSERTION_PARAMETER_NODE);
299:
300: final ModelNode node = new ModelNode(
301: Type.ASSERTION_PARAMETER_NODE, parentModel, nodeData);
302: this .addChild(node);
303:
304: return node;
305: }
306:
307: /**
308: * TODO: proper java doc
309: *
310: * Factory method that creates new policy source model node as specified by a factory method name and input parameters.
311: * Each node is created with respect to its enclosing policy source model.
312: */
313: public ModelNode createChildPolicyReferenceNode(
314: final PolicyReferenceData referenceData) {
315: checkCreateChildOperationSupportForType(Type.POLICY_REFERENCE);
316:
317: final ModelNode node = new ModelNode(parentModel, referenceData);
318: this .parentModel.addNewPolicyReference(node);
319: this .addChild(node);
320:
321: return node;
322: }
323:
324: Collection<ModelNode> getContent() {
325: return unmodifiableViewOnContent;
326: }
327:
328: // Collection<ModelNode> getAssertionParameterNodeChildren() {
329: // Collection<ModelNode> result = null;
330: //
331: // if (isAssertionRelatedNode()) {
332: //
333: // result = new LinkedList<ModelNode>();
334: //
335: // for (ModelNode child : content) {
336: // if (child.type == Type.ASSERTION_PARAMETER_NODE) {
337: // result.add(child);
338: // }
339: // }
340: // }
341: //
342: // return result;
343: // }
344: //
345: /**
346: * Sets the parent model reference on the node and its children. The method may be invoked only on the root node
347: * of the policy source model (or - in general - on a model node that dose not reference a parent node). Otherwise an
348: * exception is thrown.
349: *
350: * @param model new parent policy source model to be set.
351: * @throws IllegalAccessException in case this node references a parent node (i.e. is not a root node of the model).
352: */
353: void setParentModel(final PolicySourceModel model)
354: throws IllegalAccessException {
355: if (parentNode != null) {
356: throw LOGGER
357: .logSevereException(new IllegalAccessException(
358: LocalizationMessages
359: .WSP_0049_PARENT_MODEL_CAN_NOT_BE_CHANGED()));
360: }
361:
362: this .updateParentModelReference(model);
363: }
364:
365: /**
366: * The method updates the parentModel reference on current model node instance and all of it's children
367: *
368: * @param model new policy source model reference.
369: */
370: private void updateParentModelReference(
371: final PolicySourceModel model) {
372: this .parentModel = model;
373:
374: for (ModelNode child : content) {
375: child.updateParentModelReference(model);
376: }
377: }
378:
379: /**
380: * Returns the parent policy source model that contains this model node.
381: *
382: * @return the parent policy source model
383: */
384: public PolicySourceModel getParentModel() {
385: return parentModel;
386: }
387:
388: /**
389: * Returns the type of this policy source model node.
390: *
391: * @return actual type of this policy source model node
392: */
393: public ModelNode.Type getType() {
394: return type;
395: }
396:
397: /**
398: * Returns the parent referenced by this policy source model node.
399: *
400: * @return current parent of this policy source model node or {@code null} if the node does not have a parent currently.
401: */
402: public ModelNode getParentNode() {
403: return parentNode;
404: }
405:
406: /**
407: * Returns the data for this policy source model node (if any). The model node data are expected to be not {@code null} only in
408: * case the type of this node is ASSERTION or ASSERTION_PARAMETER_NODE.
409: *
410: * @return the data of this policy source model node or {@code null} if the node does not have any data associated to it
411: * attached.
412: */
413: public AssertionData getNodeData() {
414: return nodeData;
415: }
416:
417: /**
418: * Returns the policy reference data for this policy source model node. The policy reference data are expected to be not {@code null} only in
419: * case the type of this node is POLICY_REFERENCE.
420: *
421: * @return the policy reference data for this policy source model node or {@code null} if the node does not have any policy reference data
422: * attached.
423: */
424: public PolicyReferenceData getPolicyReferenceData() {
425: return referenceData;
426: }
427:
428: /**
429: * The method may be used to set or replace assertion data set for this node. If there are assertion data set already,
430: * those are replaced by a new reference and eventualy returned from the method.
431: * <p/>
432: * This method is supported only in case this model node instance's type is {@code ASSERTION} or {@code ASSERTION_PARAMETER_NODE}.
433: * If used from other node types, an exception is thrown.
434: *
435: * @param newData new assertion data to be set.
436: * @return old and replaced assertion data if any or {@code null} otherwise.
437: *
438: * @throws UnsupportedOperationException in case this method is called on nodes of type other than {@code ASSERTION}
439: * or {@code ASSERTION_PARAMETER_NODE}
440: */
441: public AssertionData setOrReplaceNodeData(
442: final AssertionData newData) {
443: if (!isAssertionRelatedNode()) {
444: throw LOGGER
445: .logSevereException(new UnsupportedOperationException(
446: LocalizationMessages
447: .WSP_0051_OPERATION_NOT_SUPPORTED_FOR_THIS_BUT_ASSERTION_RELATED_NODE_TYPE(type)));
448: }
449:
450: final AssertionData oldData = this .nodeData;
451: this .nodeData = newData;
452:
453: return oldData;
454: }
455:
456: /**
457: * The method specifies whether the model node instance represents assertion related node, it means whether its type
458: * is 'ASSERTION' or 'ASSERTION_PARAMETER_NODE'. This is, for example, the way to determine whether the node supports
459: * setting a {@link AssertionData} object via {@link #setOrReplaceNodeData(AssertionData)} method or not.
460: *
461: * @return {@code true} or {@code false} according to whether the node instance represents assertion related node or not.
462: */
463: boolean isAssertionRelatedNode() {
464: return type == Type.ASSERTION
465: || type == Type.ASSERTION_PARAMETER_NODE;
466: }
467:
468: /**
469: * Appends the specified child node to the end of the children list of this node and sets it's parent to reference
470: * this node.
471: *
472: * @param child node to be appended to the children list of this node.
473: * @return {@code true} (as per the general contract of the {@code Collection.add} method).
474: *
475: * @throws NullPointerException if the specified node is {@code null}.
476: * @throws IllegalArgumentException if child has a parent node set already to point to some node
477: */
478: private boolean addChild(final ModelNode child) {
479: content.add(child);
480: child.parentNode = this ;
481:
482: return true;
483: }
484:
485: /**
486: *
487: */
488: void setReferencedModel(final PolicySourceModel model) {
489: if (this .type != Type.POLICY_REFERENCE) {
490: throw LOGGER
491: .logSevereException(new UnsupportedOperationException(
492: LocalizationMessages
493: .WSP_0050_OPERATION_NOT_SUPPORTED_FOR_THIS_BUT_POLICY_REFERENCE_NODE_TYPE(type)));
494: }
495:
496: referencedModel = model;
497: }
498:
499: PolicySourceModel getReferencedModel() {
500: return referencedModel;
501: }
502:
503: /**
504: * Returns the number of child policy source model nodes. If this model node contains
505: * more than {@code Integer.MAX_VALUE} children, returns {@code Integer.MAX_VALUE}.
506: *
507: * @return the number of children of this node.
508: */
509: public int childrenSize() {
510: return content.size();
511: }
512:
513: /**
514: * Returns true if the node has at least one child node.
515: *
516: * @return true if the node has at least one child node, false otherwise.
517: */
518: public boolean hasChildren() {
519: return !content.isEmpty();
520: }
521:
522: /**
523: * Iterates through all child nodes.
524: *
525: * @return An iterator for the child nodes
526: */
527: public Iterator<ModelNode> iterator() {
528: return content.iterator();
529: }
530:
531: /**
532: * An {@code Object.equals(Object obj)} method override. Method ignores the parent source model. It means that two
533: * model nodes may be the same even if they belong to different models.
534: * <p/>
535: * If parent model comparison is desired, it must be accomplished separately. To perform that, the reference equality
536: * test is sufficient ({@code nodeA.getParentModel() == nodeB.getParentModel()}), since all model nodes are created
537: * for specific model instances.
538: */
539: public boolean equals(final Object obj) {
540: if (this == obj) {
541: return true;
542: }
543:
544: if (!(obj instanceof ModelNode)) {
545: return false;
546: }
547:
548: boolean result = true;
549: final ModelNode that = (ModelNode) obj;
550:
551: result = result && this .type.equals(that.type);
552: // result = result && ((this.parentNode == null) ? that.parentNode == null : this.parentNode.equals(that.parentNode));
553: result = result
554: && ((this .nodeData == null) ? that.nodeData == null
555: : this .nodeData.equals(that.nodeData));
556: result = result
557: && ((this .content == null) ? that.content == null
558: : this .content.equals(that.content));
559:
560: return result;
561: }
562:
563: /**
564: * An {@code Object.hashCode()} method override.
565: */
566: public int hashCode() {
567: int result = 17;
568:
569: result = 37 * result + this .type.hashCode();
570: result = 37
571: * result
572: + ((this .parentNode == null) ? 0 : this .parentNode
573: .hashCode());
574: result = 37
575: * result
576: + ((this .nodeData == null) ? 0 : this .nodeData
577: .hashCode());
578: result = 37 * result + this .content.hashCode();
579:
580: return result;
581: }
582:
583: /**
584: * Returns a string representation of the object. In general, the <code>toString</code> method
585: * returns a string that "textually represents" this object.
586: *
587: * @return a string representation of the object.
588: */
589: public String toString() {
590: return toString(0, new StringBuffer()).toString();
591: }
592:
593: /**
594: * A helper method that appends indented string representation of this instance to the input string buffer.
595: *
596: * @param indentLevel indentation level to be used.
597: * @param buffer buffer to be used for appending string representation of this instance
598: * @return modified buffer containing new string representation of the instance
599: */
600: public StringBuffer toString(final int indentLevel,
601: final StringBuffer buffer) {
602: final String indent = PolicyUtils.Text
603: .createIndent(indentLevel);
604: final String innerIndent = PolicyUtils.Text
605: .createIndent(indentLevel + 1);
606:
607: buffer.append(indent).append(type).append(" {").append(
608: PolicyUtils.Text.NEW_LINE);
609: if (type == Type.ASSERTION) {
610: if (nodeData == null) {
611: buffer.append(innerIndent).append(
612: "no assertion data set");
613: } else {
614: nodeData.toString(indentLevel + 1, buffer);
615: }
616: buffer.append(PolicyUtils.Text.NEW_LINE);
617: } else if (type == Type.POLICY_REFERENCE) {
618: if (referenceData == null) {
619: buffer.append(innerIndent).append(
620: "no policy reference data set");
621: } else {
622: referenceData.toString(indentLevel + 1, buffer);
623: }
624: buffer.append(PolicyUtils.Text.NEW_LINE);
625: }
626:
627: if (content.size() > 0) {
628: for (ModelNode child : content) {
629: child.toString(indentLevel + 1, buffer).append(
630: PolicyUtils.Text.NEW_LINE);
631: }
632: } else {
633: buffer.append(innerIndent).append("no child nodes").append(
634: PolicyUtils.Text.NEW_LINE);
635: }
636:
637: buffer.append(indent).append('}');
638: return buffer;
639: }
640:
641: protected ModelNode clone() throws CloneNotSupportedException {
642: final ModelNode clone = (ModelNode) super .clone();
643:
644: if (this .nodeData != null) {
645: clone.nodeData = this .nodeData.clone();
646: }
647:
648: // no need to clone PolicyReferenceData, since those are immutable
649:
650: if (this .referencedModel != null) {
651: clone.referencedModel = this .referencedModel.clone();
652: }
653:
654: clone.content = new LinkedList<ModelNode>();
655: clone.unmodifiableViewOnContent = Collections
656: .unmodifiableCollection(clone.content);
657:
658: for (ModelNode this Child : this .content) {
659: clone.addChild(this Child.clone());
660: }
661:
662: return clone;
663: }
664:
665: public PolicyReferenceData getReferenceData() {
666: return referenceData;
667: }
668:
669: }
|