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 java.util.HashMap;
043: import java.util.HashSet;
044: import java.util.Map;
045: import java.util.Set;
046: import javax.xml.namespace.QName;
047:
048: import com.sun.xml.ws.policy.privateutil.PolicyUtils;
049: import java.io.Serializable;
050:
051: /**
052: * Wrapper class for possible data that each 'assertion' and 'assertion parameter content' policy source model node may
053: * have attached.
054: * <p/>
055: * These data, when stored in an 'assertion' model node, are intended to be used as input parameter when creating
056: * {@link com.sun.xml.ws.policy.PolicyAssertion} objects via {@link com.sun.xml.ws.policy.spi.PolicyAssertionCreator}
057: * implementations.
058: *
059: * @author Marek Potociar (marek.potociar@sun.com)
060: */
061: public final class AssertionData implements Cloneable, Serializable {
062: private static final PolicyLogger LOGGER = PolicyLogger
063: .getLogger(AssertionData.class);
064:
065: private final QName name;
066: private final String value;
067: private Map<QName, String> attributes = new HashMap<QName, String>();
068: private ModelNode.Type type;
069:
070: /**
071: * Constructs assertion data wrapper instance for an assertion that does not
072: * contain any value nor any attributes.
073: *
074: * @param name the FQN of the assertion
075: *
076: * @throws IllegalArgumentException in case the {@code type} parameter is not
077: * {@link ModelNode.Type#ASSERTION ASSERTION} or
078: * {@link ModelNode.Type#ASSERTION_PARAMETER_NODE ASSERTION_PARAMETER_NODE}
079: */
080: public static AssertionData createAssertionData(final QName name)
081: throws IllegalArgumentException {
082: return new AssertionData(name, null, null,
083: ModelNode.Type.ASSERTION);
084: }
085:
086: /**
087: * Constructs assertion data wrapper instance for an assertion parameter that
088: * does not contain any value nor any attributes.
089: *
090: * @param name the FQN of the assertion parameter
091: *
092: * @throws IllegalArgumentException in case the {@code type} parameter is not
093: * {@link ModelNode.Type#ASSERTION ASSERTION} or
094: * {@link ModelNode.Type#ASSERTION_PARAMETER_NODE ASSERTION_PARAMETER_NODE}
095: */
096: public static AssertionData createAssertionParameterData(
097: final QName name) throws IllegalArgumentException {
098: return new AssertionData(name, null, null,
099: ModelNode.Type.ASSERTION_PARAMETER_NODE);
100: }
101:
102: /**
103: * Constructs assertion data wrapper instance for an assertion that does
104: * contain a value or attributes.
105: *
106: * @param name the FQN of the assertion
107: * @param value a {@link String} representation of model node value
108: * @param attributes map of model node's <attribute name, attribute value> pairs
109: *
110: * @throws IllegalArgumentException in case the {@code type} parameter is not
111: * {@link ModelNode.Type#ASSERTION ASSERTION} or
112: * {@link ModelNode.Type#ASSERTION_PARAMETER_NODE ASSERTION_PARAMETER_NODE}
113: */
114: public static AssertionData createAssertionData(final QName name,
115: final String value, final Map<QName, String> attributes)
116: throws IllegalArgumentException {
117: return new AssertionData(name, value, attributes,
118: ModelNode.Type.ASSERTION);
119: }
120:
121: /**
122: * Constructs assertion data wrapper instance for an assertion parameter that
123: * contains a value or attributes
124: *
125: * @param name the FQN of the assertion parameter
126: * @param value a {@link String} representation of model node value
127: * @param attributes map of model node's <attribute name, attribute value> pairs
128: *
129: * @throws IllegalArgumentException in case the {@code type} parameter is not
130: * {@link ModelNode.Type#ASSERTION ASSERTION} or
131: * {@link ModelNode.Type#ASSERTION_PARAMETER_NODE ASSERTION_PARAMETER_NODE}
132: */
133: public static AssertionData createAssertionParameterData(
134: final QName name, final String value,
135: final Map<QName, String> attributes)
136: throws IllegalArgumentException {
137: return new AssertionData(name, value, attributes,
138: ModelNode.Type.ASSERTION_PARAMETER_NODE);
139: }
140:
141: /**
142: * Constructs assertion data wrapper instance for an assertion or assertion parameter that contains a value or
143: * some attributes. Whether the data wrapper is constructed for assertion or assertion parameter node is distinguished by
144: * the supplied {@code type} parameter.
145: *
146: * @param name the FQN of the assertion or assertion parameter
147: * @param value a {@link String} representation of model node value
148: * @param attributes map of model node's <attribute name, attribute value> pairs
149: * @param type specifies whether the data will belong to the assertion or assertion parameter node. This is
150: * a workaround solution that allows us to transfer this information about the owner node to
151: * a policy assertion instance factory without actualy having to touch the {@link PolicyAssertionCreator}
152: * interface and protected {@link PolicyAssertion} constructors.
153: *
154: * @throws IllegalArgumentException in case the {@code type} parameter is not
155: * {@link ModelNode.Type#ASSERTION ASSERTION} or
156: * {@link ModelNode.Type#ASSERTION_PARAMETER_NODE ASSERTION_PARAMETER_NODE}
157: */
158: AssertionData(QName name, String value,
159: Map<QName, String> attributes, ModelNode.Type type)
160: throws IllegalArgumentException {
161: this .name = name;
162: this .value = value;
163: if (attributes != null) {
164: this .attributes.putAll(attributes);
165: }
166: setModelNodeType(type);
167: }
168:
169: private void setModelNodeType(final ModelNode.Type type)
170: throws IllegalArgumentException {
171: if (type == ModelNode.Type.ASSERTION
172: || type == ModelNode.Type.ASSERTION_PARAMETER_NODE) {
173: this .type = type;
174: } else {
175: throw LOGGER
176: .logSevereException(new IllegalArgumentException(
177: LocalizationMessages
178: .WSP_0074_CANNOT_CREATE_ASSERTION_BAD_TYPE(
179: type,
180: ModelNode.Type.ASSERTION,
181: ModelNode.Type.ASSERTION_PARAMETER_NODE)));
182: }
183: }
184:
185: /**
186: * TODO: javadoc
187: */
188: AssertionData(final AssertionData data) {
189: this .name = data.name;
190: this .value = data.value;
191: if (attributes != null) {
192: this .attributes.putAll(data.attributes);
193: }
194: this .type = data.type;
195: }
196:
197: protected AssertionData clone() throws CloneNotSupportedException {
198: final AssertionData clone = (AssertionData) super .clone();
199:
200: clone.attributes = new HashMap<QName, String>(this .attributes);
201:
202: return clone;
203: }
204:
205: /**
206: * TODO: javadoc
207: */
208: public boolean containsAttribute(final QName name) {
209: synchronized (attributes) {
210: return attributes.containsKey(name);
211: }
212: }
213:
214: /**
215: * An {@code Object.equals(Object obj)} method override.
216: */
217: public boolean equals(final Object obj) {
218: if (this == obj) {
219: return true;
220: }
221:
222: if (!(obj instanceof AssertionData)) {
223: return false;
224: }
225:
226: boolean result = true;
227: final AssertionData that = (AssertionData) obj;
228:
229: result = result && this .name.equals(that.name);
230: result = result
231: && ((this .value == null) ? that.value == null
232: : this .value.equals(that.value));
233: synchronized (attributes) {
234: result = result
235: && ((this .attributes == null) ? that.attributes == null
236: : this .attributes.equals(that.attributes));
237: }
238:
239: return result;
240: }
241:
242: /**
243: * TODO: javadoc
244: */
245: public String getAttributeValue(final QName name) {
246: synchronized (attributes) {
247: return attributes.get(name);
248: }
249: }
250:
251: /**
252: * Returns the disconnected map of attributes attached to the assertion.
253: * <p/>
254: * 'Disconnected' means, that the result of this method will not be synchronized with any consequent assertion's attribute modification. It is
255: * also important to notice that a manipulation with returned set of attributes will not have any effect on the actual assertion's
256: * attributes.
257: *
258: * @return disconnected map of attributes attached to the assertion.
259: */
260: public Map<QName, String> getAttributes() {
261: synchronized (attributes) {
262: return new HashMap<QName, String>(attributes);
263: }
264: }
265:
266: /**
267: * Returns the disconnected set of attributes attached to the assertion. Each attribute is represented as a single
268: * {@code Map.Entry<attributeName, attributeValue>} element.
269: * <p/>
270: * 'Disconnected' means, that the result of this method will not be synchronized with any consequent assertion's attribute modification. It is
271: * also important to notice that a manipulation with returned set of attributes will not have any effect on the actual assertion's
272: * attributes.
273: *
274: * @return disconnected set of attributes attached to the assertion.
275: */
276: public Set<Map.Entry<QName, String>> getAttributesSet() {
277: synchronized (attributes) {
278: return new HashSet<Map.Entry<QName, String>>(attributes
279: .entrySet());
280: }
281: }
282:
283: /**
284: * Returns the name of the assertion.
285: *
286: * @return assetion's name
287: */
288: public QName getName() {
289: return name;
290: }
291:
292: /**
293: * Returns the value of the assertion.
294: *
295: * @return assetion's value
296: */
297: public String getValue() {
298: return value;
299: }
300:
301: /**
302: * An {@code Object.hashCode()} method override.
303: */
304: public int hashCode() {
305: int result = 17;
306:
307: result = 37 * result + this .name.hashCode();
308: result = 37 * result
309: + ((this .value == null) ? 0 : this .value.hashCode());
310: synchronized (attributes) {
311: result = 37
312: * result
313: + ((this .attributes == null) ? 0 : this .attributes
314: .hashCode());
315: }
316: return result;
317: }
318:
319: /**
320: * Method specifies whether the assertion data contain proprietary visibility element set to "private" value.
321: *
322: * @return {@code 'true'} if the attribute is present and set properly (i.e. the node containing this assertion data instance should
323: * not be marshalled int generated WSDL documents). Returns {@code false} otherwise.
324: */
325: public boolean isPrivateAttributeSet() {
326: return PolicyConstants.VISIBILITY_VALUE_PRIVATE
327: .equals(getAttributeValue(PolicyConstants.VISIBILITY_ATTRIBUTE));
328: }
329:
330: /**
331: * TODO: javadoc
332: */
333: public String removeAttribute(final QName name) {
334: synchronized (attributes) {
335: return attributes.remove(name);
336: }
337: }
338:
339: /**
340: * TODO: javadoc
341: */
342: public void setAttribute(final QName name, final String value) {
343: synchronized (attributes) {
344: attributes.put(name, value);
345: }
346: }
347:
348: /**
349: * TODO: javadoc
350: */
351: public void setOptionalAttribute(final boolean value) {
352: setAttribute(PolicyConstants.OPTIONAL, Boolean.toString(value));
353: }
354:
355: /**
356: * An {@code Object.toString()} method override.
357: */
358: public String toString() {
359: return toString(0, new StringBuffer()).toString();
360: }
361:
362: /**
363: * A helper method that appends indented string representation of this instance to the input string buffer.
364: *
365: * @param indentLevel indentation level to be used.
366: * @param buffer buffer to be used for appending string representation of this instance
367: * @return modified buffer containing new string representation of the instance
368: */
369: public StringBuffer toString(final int indentLevel,
370: final StringBuffer buffer) {
371: final String indent = PolicyUtils.Text
372: .createIndent(indentLevel);
373: final String innerIndent = PolicyUtils.Text
374: .createIndent(indentLevel + 1);
375: final String innerDoubleIndent = PolicyUtils.Text
376: .createIndent(indentLevel + 2);
377:
378: buffer.append(indent);
379: if (type == ModelNode.Type.ASSERTION) {
380: buffer.append("assertion data {");
381: } else {
382: buffer.append("assertion parameter data {");
383: }
384: buffer.append(PolicyUtils.Text.NEW_LINE);
385:
386: buffer.append(innerIndent).append("namespace = '").append(
387: name.getNamespaceURI()).append('\'').append(
388: PolicyUtils.Text.NEW_LINE);
389: buffer.append(innerIndent).append("prefix = '").append(
390: name.getPrefix()).append('\'').append(
391: PolicyUtils.Text.NEW_LINE);
392: buffer.append(innerIndent).append("local name = '").append(
393: name.getLocalPart()).append('\'').append(
394: PolicyUtils.Text.NEW_LINE);
395: buffer.append(innerIndent).append("value = '").append(value)
396: .append('\'').append(PolicyUtils.Text.NEW_LINE);
397: synchronized (attributes) {
398: if (attributes.isEmpty()) {
399: buffer.append(innerIndent).append("no attributes");
400: } else {
401:
402: buffer.append(innerIndent).append("attributes {")
403: .append(PolicyUtils.Text.NEW_LINE);
404: for (Map.Entry<QName, String> entry : attributes
405: .entrySet()) {
406: final QName aName = entry.getKey();
407: buffer.append(innerDoubleIndent).append("name = '")
408: .append(aName.getNamespaceURI())
409: .append(':').append(aName.getLocalPart());
410: buffer.append("', value = '").append(
411: entry.getValue()).append('\'').append(
412: PolicyUtils.Text.NEW_LINE);
413: }
414: buffer.append(innerIndent).append('}');
415: }
416: }
417:
418: buffer.append(PolicyUtils.Text.NEW_LINE).append(indent).append(
419: '}');
420:
421: return buffer;
422: }
423:
424: public ModelNode.Type getNodeType() {
425: return type;
426: }
427:
428: }
|