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.PolicyException;
041: import com.sun.xml.ws.policy.privateutil.LocalizationMessages;
042: import com.sun.xml.ws.policy.privateutil.PolicyLogger;
043: import com.sun.xml.ws.policy.privateutil.PolicyUtils;
044: import java.util.Collection;
045: import java.util.HashMap;
046: import java.util.HashSet;
047: import java.util.LinkedList;
048: import java.util.List;
049: import java.util.Map;
050: import java.util.Map.Entry;
051: import java.util.Queue;
052: import java.util.Set;
053: import javax.xml.namespace.QName;
054:
055: /**
056: * This class is a root of unmarshaled policy source structure. Each instance of the class contains factory method
057: * to create new {@link com.sun.xml.ws.policy.sourcemodel.ModelNode} instances associated with the actual model instance.
058: *
059: * @author Marek Potociar
060: */
061: public final class PolicySourceModel implements Cloneable {
062: private static final PolicyLogger LOGGER = PolicyLogger
063: .getLogger(PolicySourceModel.class);
064:
065: // TODO: move responisbility for default namespacing to the domain SPI implementation
066: private static final Map<String, String> defaultNamespaceToPrefixMap = new HashMap<String, String>();
067: static {
068: defaultNamespaceToPrefixMap.put(
069: PolicyConstants.POLICY_NAMESPACE_URI,
070: PolicyConstants.POLICY_NAMESPACE_PREFIX);
071: defaultNamespaceToPrefixMap.put(
072: PolicyConstants.SUN_POLICY_NAMESPACE_URI,
073: PolicyConstants.SUN_POLICY_NAMESPACE_PREFIX);
074:
075: // defaultNamespaceToPrefixMap.put(com.sun.xml.ws.encoding.policy.EncodingConstants.OPTIMIZED_MIME_NS, "");
076: // defaultNamespaceToPrefixMap.put(com.sun.xml.ws.encoding.policy.EncodingConstants.ENCODING_NS, "");
077: defaultNamespaceToPrefixMap
078: .put(
079: com.sun.xml.ws.encoding.policy.EncodingConstants.SUN_ENCODING_CLIENT_NS,
080: "cenc");
081: defaultNamespaceToPrefixMap
082: .put(
083: com.sun.xml.ws.encoding.policy.EncodingConstants.SUN_FI_SERVICE_NS,
084: "fi");
085:
086: defaultNamespaceToPrefixMap.put(
087: com.sun.xml.ws.security.impl.policy.Constants.TRUST_NS,
088: "wst");
089: defaultNamespaceToPrefixMap
090: .put(
091: com.sun.xml.ws.security.impl.policy.Constants.SECURITY_POLICY_NS,
092: "sp");
093: defaultNamespaceToPrefixMap
094: .put(
095: com.sun.xml.ws.security.impl.policy.Constants.UTILITY_NS,
096: PolicyConstants.WSU_NAMESPACE_PREFIX);
097: defaultNamespaceToPrefixMap
098: .put(
099: com.sun.xml.ws.security.impl.policy.Constants.SUN_WSS_SECURITY_CLIENT_POLICY_NS,
100: "csp");
101: defaultNamespaceToPrefixMap
102: .put(
103: com.sun.xml.ws.security.impl.policy.Constants.SUN_WSS_SECURITY_SERVER_POLICY_NS,
104: "ssp");
105: defaultNamespaceToPrefixMap
106: .put(
107: com.sun.xml.ws.security.impl.policy.Constants.SUN_TRUST_CLIENT_SECURITY_POLICY_NS,
108: "ctp");
109: defaultNamespaceToPrefixMap
110: .put(
111: com.sun.xml.ws.security.impl.policy.Constants.SUN_TRUST_SERVER_SECURITY_POLICY_NS,
112: "stp");
113: defaultNamespaceToPrefixMap
114: .put(
115: com.sun.xml.ws.security.impl.policy.Constants.SUN_SECURE_CLIENT_CONVERSATION_POLICY_NS,
116: "cscp");
117: defaultNamespaceToPrefixMap
118: .put(
119: com.sun.xml.ws.security.impl.policy.Constants.SUN_SECURE_SERVER_CONVERSATION_POLICY_NS,
120: "sscp");
121:
122: defaultNamespaceToPrefixMap.put(
123: com.sun.xml.ws.rm.Constants.version, "wsrmp");
124: defaultNamespaceToPrefixMap.put(
125: com.sun.xml.ws.rm.Constants.microsoftVersion, "msrmp");
126: defaultNamespaceToPrefixMap.put(
127: com.sun.xml.ws.rm.Constants.sunVersion, "sunrmp");
128: defaultNamespaceToPrefixMap
129: .put(com.sun.xml.ws.rm.Constants.sunClientVersion,
130: "sunrmcp");
131:
132: defaultNamespaceToPrefixMap
133: .put(
134: com.sun.xml.ws.transport.tcp.wsit.TCPConstants.TCPTRANSPORT_POLICY_NAMESPACE_URI,
135: "soaptcpsvc");
136: defaultNamespaceToPrefixMap
137: .put(
138: com.sun.xml.ws.transport.tcp.wsit.TCPConstants.CLIENT_TRANSPORT_NS,
139: "transport");
140: defaultNamespaceToPrefixMap
141: .put(
142: com.sun.xml.ws.transport.tcp.wsit.TCPConstants.TCPTRANSPORT_CONNECTION_MANAGEMENT_NAMESPACE_URI,
143: "soaptcp");
144:
145: defaultNamespaceToPrefixMap
146: .put(
147: com.sun.xml.ws.api.addressing.AddressingVersion.MEMBER.policyNsUri,
148: "wsap");
149: defaultNamespaceToPrefixMap
150: .put(
151: com.sun.xml.ws.api.addressing.AddressingVersion.MEMBER.nsUri,
152: "wsa");
153: defaultNamespaceToPrefixMap
154: .put(
155: com.sun.xml.ws.api.addressing.AddressingVersion.W3C.policyNsUri,
156: "wsapw3c");
157: defaultNamespaceToPrefixMap
158: .put(
159: com.sun.xml.ws.api.addressing.AddressingVersion.W3C.nsUri,
160: "wsaw3c");
161:
162: defaultNamespaceToPrefixMap.put(
163: com.sun.xml.ws.tx.common.Constants.WSAT_SOAP_NSURI,
164: "wsat");
165: }
166:
167: private ModelNode rootNode;
168: private String policyId;
169: private String policyName;
170:
171: private final List<ModelNode> references = new LinkedList<ModelNode>(); // links to policy reference nodes
172: private boolean expanded = false;
173:
174: /**
175: * Factory method that creates new policy source model instance.
176: *
177: * @return newly created policy source model instance
178: */
179: public static PolicySourceModel createPolicySourceModel() {
180: return new PolicySourceModel();
181: }
182:
183: /**
184: * Factory method that creates new policy source model instance and initializes it according to parameters provided.
185: *
186: * @param policyId local policy identifier - relative URI. May be {@code null}.
187: * @param policyName global policy identifier - absolute policy expression URI. May be {@code null}.
188: * @return newly created policy source model instance with its name and id properly set
189: */
190: public static PolicySourceModel createPolicySourceModel(
191: final String policyId, final String policyName) {
192: return new PolicySourceModel(policyId, policyName);
193: }
194:
195: /**
196: * Private constructor that creats new policy source model instance without any
197: * id or name identifier. The namespace-to-prefix map is initialized with mapping
198: * of policy namespace to the default value set by
199: * {@link PolicyConstants#POLICY_NAMESPACE_PREFIX POLICY_NAMESPACE_PREFIX constant}
200: */
201: private PolicySourceModel() {
202: this .rootNode = ModelNode.createRootPolicyNode(this );
203: }
204:
205: /**
206: * Private constructor that creats new policy source model instance with given
207: * id or name identifier.
208: *
209: * @param policyId relative policy reference within an XML document. May be {@code null}.
210: * @param policyName absloute IRI of policy expression. May be {@code null}.
211: */
212: private PolicySourceModel(String policyId, String policyName) {
213: this ();
214: this .policyId = policyId;
215: this .policyName = policyName;
216: }
217:
218: /**
219: * Returns a root node of this policy source model. It is allways of POLICY type.
220: *
221: * @return root policy source model node - allways of POLICY type.
222: */
223: public ModelNode getRootNode() {
224: return rootNode;
225: }
226:
227: /**
228: * Returns a policy name of this policy source model.
229: *
230: * @return policy name.
231: */
232: public String getPolicyName() {
233: return policyName;
234: }
235:
236: /**
237: * Returns a policy ID of this policy source model.
238: *
239: * @return policy ID.
240: */
241: public String getPolicyId() {
242: return policyId;
243: }
244:
245: /**
246: * Provides information about how namespaces used in this {@link PolicySourceModel}
247: * instance should be mapped to thier default prefixes when marshalled.
248: *
249: * @return immutable map that holds information about namespaces used in the
250: * model and their mapping to prefixes that should be used when marshalling
251: * this model.
252: */
253: Map<String, String> getNamespaceToPrefixMapping() {
254: final Map<String, String> nsToPrefixMap = new HashMap<String, String>();
255:
256: final Collection<String> namespaces = getUsedNamespaces();
257: for (String namespace : namespaces) {
258: final String prefix = getDefaultPrefix(namespace);
259: if (prefix != null) {
260: nsToPrefixMap.put(namespace, prefix);
261: }
262: }
263:
264: return nsToPrefixMap;
265: }
266:
267: /**
268: * An {@code Object.equals(Object obj)} method override.
269: * <p/>
270: * When child nodes are tested for equality, the parent policy source model is not considered. Thus two different
271: * policy source models instances may be equal based on their node content.
272: */
273: public boolean equals(final Object obj) {
274: if (this == obj) {
275: return true;
276: }
277:
278: if (!(obj instanceof PolicySourceModel)) {
279: return false;
280: }
281:
282: boolean result = true;
283: final PolicySourceModel that = (PolicySourceModel) obj;
284:
285: result = result
286: && ((this .policyId == null) ? that.policyId == null
287: : this .policyId.equals(that.policyId));
288: result = result
289: && ((this .policyName == null) ? that.policyName == null
290: : this .policyName.equals(that.policyName));
291: result = result && this .rootNode.equals(that.rootNode);
292: // result = result && ((this.xxx == null) ? that.xxx == null : this.xxx.equals(that.xxx));
293:
294: return result;
295: }
296:
297: /**
298: * An {@code Object.hashCode()} method override.
299: */
300: public int hashCode() {
301: int result = 17;
302:
303: result = 37
304: * result
305: + ((this .policyId == null) ? 0 : this .policyId
306: .hashCode());
307: result = 37
308: * result
309: + ((this .policyName == null) ? 0 : this .policyName
310: .hashCode());
311: result = 37 * result + this .rootNode.hashCode();
312: // result = 37 * result + ((this.xxx == null) ? 0 : this.xxx.hashCode());
313:
314: return result;
315: }
316:
317: /**
318: * Returns a string representation of the object. In general, the <code>toString</code> method
319: * returns a string that "textually represents" this object.
320: *
321: * @return a string representation of the object.
322: */
323: public String toString() {
324: final String innerIndent = PolicyUtils.Text.createIndent(1);
325: final StringBuffer buffer = new StringBuffer(60);
326:
327: buffer.append("Policy source model {").append(
328: PolicyUtils.Text.NEW_LINE);
329: buffer.append(innerIndent).append("policy id = '").append(
330: policyId).append('\'')
331: .append(PolicyUtils.Text.NEW_LINE);
332: buffer.append(innerIndent).append("policy name = '").append(
333: policyName).append('\'').append(
334: PolicyUtils.Text.NEW_LINE);
335: rootNode.toString(1, buffer).append(PolicyUtils.Text.NEW_LINE)
336: .append('}');
337:
338: return buffer.toString();
339: }
340:
341: protected PolicySourceModel clone()
342: throws CloneNotSupportedException {
343: final PolicySourceModel clone = (PolicySourceModel) super
344: .clone();
345:
346: clone.rootNode = this .rootNode.clone();
347: try {
348: clone.rootNode.setParentModel(this );
349: } catch (IllegalAccessException e) {
350: throw LOGGER
351: .logSevereException(
352: new CloneNotSupportedException(
353: LocalizationMessages
354: .WSP_0013_UNABLE_TO_SET_PARENT_MODEL_ON_ROOT()),
355: e);
356: }
357:
358: return clone;
359: }
360:
361: /**
362: * Returns a boolean value indicating whether this policy source model contains references to another policy source models.
363: * <p/>
364: * Every source model that references other policies must be expanded before it can be translated into a Policy objects. See
365: * {@link #expand(PolicySourceModelContext)} and {@link #isExpanded()} for more details.
366: *
367: * @return {@code true} or {code false} depending on whether this policy source model contains references to another policy source models.
368: */
369: public boolean containsPolicyReferences() {
370: return !references.isEmpty();
371: }
372:
373: /**
374: * Returns a boolean value indicating whether this policy source model contains is already expanded (i.e. contains no unexpanded
375: * policy references) or not. This means that if model does not originally contain any policy references, it is considered as expanded,
376: * thus this method returns {@code true} in such case. Also this method does not check whether the references policy source models are expanded
377: * as well, so after expanding this model a value of {@code true} is returned even if referenced models are not expanded yet. Thus each model
378: * can be considered to be fully expanded only if all policy source models stored in PolicySourceModelContext instance are expanded, provided the
379: * PolicySourceModelContext instance contains full set of policy source models.
380: * <p/>
381: * Every source model that references other policies must be expanded before it can be translated into a Policy object. See
382: * {@link #expand(PolicySourceModelContext)} and {@link #containsPolicyReferences()} for more details.
383: *
384: * @return {@code true} or {@code false} depending on whether this policy source model contains is expanded or not.
385: */
386: private boolean isExpanded() {
387: return references.isEmpty() || expanded;
388: }
389:
390: /**
391: * Expands current policy model. This means, that if this model contains any (unexpanded) policy references, then the method expands those
392: * references by placing the content of the referneced policy source models under the policy reference nodes. This operation merely creates
393: * a link between this and referenced policy source models. Thus any change in the referenced models will be visible wihtin this model as well.
394: * <p/>
395: * Please, notice that the method does not check if the referenced models are already expanded nor does the method try to expand unexpanded
396: * referenced models. This must be preformed manually within client's code. Consecutive calls of this method will have no effect.
397: * <p/>
398: * Every source model that references other policies must be expanded before it can be translated into a Policy object. See
399: * {@link #isExpanded()} and {@link #containsPolicyReferences()} for more details.
400: *
401: * @param context a policy source model context holding the set of unmarshalled policy source models within the same context.
402: */
403: public synchronized void expand(
404: final PolicySourceModelContext context)
405: throws PolicyException {
406: if (!isExpanded()) {
407: for (ModelNode reference : references) {
408: final PolicyReferenceData refData = reference
409: .getPolicyReferenceData();
410: final String digest = refData.getDigest();
411: PolicySourceModel referencedModel;
412: if (digest == null) {
413: referencedModel = context.retrieveModel(refData
414: .getReferencedModelUri());
415: } else {
416: referencedModel = context.retrieveModel(refData
417: .getReferencedModelUri(), refData
418: .getDigestAlgorithmUri(), digest);
419: }
420:
421: reference.setReferencedModel(referencedModel);
422: }
423: expanded = true;
424: }
425: }
426:
427: /**
428: * Adds new policy reference to the policy source model. The method is used by
429: * the ModelNode instances of type POLICY_REFERENCE that need to register themselves
430: * as policy references in the model.
431: *
432: * @param node policy reference model node to be registered as a policy reference
433: * in this model.
434: */
435: void addNewPolicyReference(final ModelNode node) {
436: if (node.getType() != ModelNode.Type.POLICY_REFERENCE) {
437: throw new IllegalArgumentException(
438: LocalizationMessages
439: .WSP_0042_POLICY_REFERENCE_NODE_EXPECTED_INSTEAD_OF(node
440: .getType()));
441: }
442:
443: references.add(node);
444: }
445:
446: /**
447: * Iterates through policy vocabulary and extracts set of namespaces used in
448: * the policy expression.
449: *
450: * @param policy policy instance to check fro used namespaces
451: * @return collection of used namespaces within given policy instance
452: */
453: private Collection<String> getUsedNamespaces() {
454: final Set<String> namespaces = new HashSet<String>();
455: namespaces.add(PolicyConstants.POLICY_NAMESPACE_URI);
456:
457: if (this .policyId != null) {
458: namespaces.add(PolicyConstants.WSU_NAMESPACE_URI);
459: }
460:
461: final Queue<ModelNode> nodesToBeProcessed = new LinkedList<ModelNode>();
462: nodesToBeProcessed.add(rootNode);
463:
464: ModelNode processedNode;
465: while ((processedNode = nodesToBeProcessed.poll()) != null) {
466: for (ModelNode child : processedNode.getContent()) {
467: if (child.hasChildren()) {
468: nodesToBeProcessed.offer(child);
469: }
470:
471: if (child.isAssertionRelatedNode()) {
472: final AssertionData nodeData = child.getNodeData();
473: namespaces
474: .add(nodeData.getName().getNamespaceURI());
475: if (nodeData.isPrivateAttributeSet()) {
476: namespaces
477: .add(PolicyConstants.SUN_POLICY_NAMESPACE_URI);
478: }
479:
480: for (Entry<QName, String> attribute : nodeData
481: .getAttributesSet()) {
482: namespaces.add(attribute.getKey()
483: .getNamespaceURI());
484: }
485: }
486: }
487: }
488:
489: return namespaces;
490: }
491:
492: /**
493: * Method retrieves default prefix for given namespace. Method returns null if
494: * no default prefix is defined..
495: *
496: * @param namespace to get default prefix for.
497: * @return default prefix for given namespace. May return {@code null} if the
498: * default prefix for given namespace is not defined.
499: */
500: private String getDefaultPrefix(final String namespace) {
501: return defaultNamespaceToPrefixMap.get(namespace);
502: }
503: }
|