| /* |
| * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package com.sun.xml.internal.ws.policy.jaxws; |
| |
| import com.sun.xml.internal.ws.api.policy.ModelUnmarshaller; |
| import com.sun.xml.internal.ws.policy.PolicyException; |
| import com.sun.xml.internal.ws.policy.privateutil.PolicyLogger; |
| import com.sun.xml.internal.ws.policy.sourcemodel.PolicySourceModel; |
| import com.sun.xml.internal.ws.policy.sourcemodel.wspolicy.NamespaceVersion; |
| import com.sun.xml.internal.ws.policy.sourcemodel.wspolicy.XmlToken; |
| import com.sun.xml.internal.ws.resources.PolicyMessages; |
| |
| import java.io.StringReader; |
| import java.util.HashSet; |
| import java.util.Set; |
| import javax.xml.namespace.QName; |
| import javax.xml.stream.XMLStreamConstants; |
| import javax.xml.stream.XMLStreamException; |
| import javax.xml.stream.XMLStreamReader; |
| import javax.xml.ws.WebServiceException; |
| |
| /** |
| * Provides methods to unmarshal policies from a XMLStreamReader safely |
| * |
| * @author Fabian Ritzmann |
| */ |
| public class SafePolicyReader { |
| |
| private static final PolicyLogger LOGGER = PolicyLogger.getLogger(SafePolicyReader.class); |
| |
| // urls of xml docs policies were read from |
| private final Set<String> urlsRead = new HashSet<String>(); |
| |
| private final Set<String> qualifiedPolicyUris = new HashSet<String>(); |
| |
| |
| public final class PolicyRecord { |
| PolicyRecord next; |
| PolicySourceModel policyModel; |
| Set<String> unresolvedURIs; |
| private String uri; |
| |
| PolicyRecord() { |
| // nothing to initialize |
| } |
| |
| PolicyRecord insert(final PolicyRecord insertedRec) { |
| if (null==insertedRec.unresolvedURIs || insertedRec.unresolvedURIs.isEmpty()) { |
| insertedRec.next = this; |
| return insertedRec; |
| } |
| final PolicyRecord head = this; |
| PolicyRecord oneBeforeCurrent = null; |
| PolicyRecord current; |
| for (current = head ; null != current.next ; ) { |
| if ((null != current.unresolvedURIs) && current.unresolvedURIs.contains(insertedRec.uri)) { |
| if (null == oneBeforeCurrent) { |
| insertedRec.next = current; |
| return insertedRec; |
| } else { // oneBeforeCurrent != null |
| oneBeforeCurrent.next = insertedRec; |
| insertedRec.next = current; |
| return head; |
| } // end-if-else oneBeforeCurrent == null |
| }// end-if current record depends on inserted one |
| if (insertedRec.unresolvedURIs.remove(current.uri) && (insertedRec.unresolvedURIs.isEmpty())) { |
| insertedRec.next = current.next; |
| current.next = insertedRec; |
| return head; |
| } // end-if one of unresolved URIs resolved by current record and thus unresolvedURIs empty |
| oneBeforeCurrent = current; |
| current = current.next; |
| } // end for (current = head; null!=current.next; ) |
| insertedRec.next = null; |
| current.next = insertedRec; |
| return head; |
| } |
| |
| /** |
| * Set the URI that identifies the policy. |
| * |
| * @param uri The fully qualified URI of the policy. May be a relative URI |
| * if JAX-WS did not pass on any system id. |
| * @param id The short ID of the policy. Used for error reporting. |
| * @throws PolicyException If there already is a policy recorded with the |
| * same id. |
| */ |
| public void setUri(final String uri, final String id) throws PolicyException { |
| if (qualifiedPolicyUris.contains(uri)) { |
| throw LOGGER.logSevereException(new PolicyException(PolicyMessages.WSP_1020_DUPLICATE_ID(id))); |
| } |
| this.uri = uri; |
| qualifiedPolicyUris.add(uri); |
| } |
| |
| public String getUri() { |
| return this.uri; |
| } |
| |
| @Override |
| public String toString() { |
| String result = uri; |
| if (null!=next) { |
| result += "->" + next.toString(); |
| } |
| return result; |
| } |
| } |
| |
| |
| /** |
| * Reads a policy expression from the XML stream. |
| * |
| * The XMLStreamReader should be in START_ELEMENT state and point to the policy element. |
| * The content of the stream is copied and then the copy is unmarshalled. The result |
| * is returned as a PolicyRecord. |
| * |
| * @param reader The XMLStreamReader should be in START_ELEMENT state and point to the policy element. |
| * @param baseUrl The system id of the document read by the reader. |
| * @return The policy that was read from the XML stream. |
| */ |
| public PolicyRecord readPolicyElement(final XMLStreamReader reader, final String baseUrl) { |
| if ((null == reader) || (!reader.isStartElement())) { |
| return null; |
| } |
| final StringBuffer elementCode = new StringBuffer(); |
| final PolicyRecord policyRec = new PolicyRecord(); |
| final QName elementName = reader.getName(); |
| boolean insidePolicyReferenceAttr; |
| int depth = 0; |
| try{ |
| do { |
| switch (reader.getEventType()) { |
| case XMLStreamConstants.START_ELEMENT: // process start of next element |
| QName curName = reader.getName(); |
| insidePolicyReferenceAttr = NamespaceVersion.resolveAsToken(curName) == XmlToken.PolicyReference; |
| if (elementName.equals(curName)) { // it is our element ! |
| depth++; // we are then deeper |
| } |
| final StringBuffer xmlnsCode = new StringBuffer(); // take care about namespaces as well |
| final Set<String> tmpNsSet = new HashSet<String>(); |
| if ((null == curName.getPrefix()) || ("".equals(curName.getPrefix()))) { // no prefix |
| elementCode |
| .append('<') // start tag |
| .append(curName.getLocalPart()); |
| xmlnsCode |
| .append(" xmlns=\"") |
| .append(curName.getNamespaceURI()) |
| .append('"'); |
| |
| } else { // prefix presented |
| elementCode |
| .append('<') // start tag |
| .append(curName.getPrefix()) |
| .append(':') |
| .append(curName.getLocalPart()); |
| xmlnsCode |
| .append(" xmlns:") |
| .append(curName.getPrefix()) |
| .append("=\"") |
| .append(curName.getNamespaceURI()) |
| .append('"'); |
| tmpNsSet.add(curName.getPrefix()); |
| } |
| final int attrCount = reader.getAttributeCount(); // process element attributes |
| final StringBuffer attrCode = new StringBuffer(); |
| for (int i=0; i < attrCount; i++) { |
| boolean uriAttrFlg = false; |
| if (insidePolicyReferenceAttr && "URI".equals( |
| reader.getAttributeName(i).getLocalPart())) { // PolicyReference found |
| uriAttrFlg = true; |
| if (null == policyRec.unresolvedURIs) { // first such URI found |
| policyRec.unresolvedURIs = new HashSet<String>(); // initialize URIs set |
| } |
| policyRec.unresolvedURIs.add( // add the URI |
| relativeToAbsoluteUrl(reader.getAttributeValue(i), baseUrl)); |
| } // end-if PolicyReference attribute found |
| if ("xmlns".equals(reader.getAttributePrefix(i)) && tmpNsSet.contains(reader.getAttributeLocalName(i))) { |
| continue; // do not append already defined ns |
| } |
| if ((null == reader.getAttributePrefix(i)) || ("".equals(reader.getAttributePrefix(i)))) { // no attribute prefix |
| attrCode |
| .append(' ') |
| .append(reader.getAttributeLocalName(i)) |
| .append("=\"") |
| .append(uriAttrFlg ? relativeToAbsoluteUrl(reader.getAttributeValue(i), baseUrl) : reader.getAttributeValue(i)) |
| .append('"'); |
| } else { // prefix`presented |
| attrCode |
| .append(' ') |
| .append(reader.getAttributePrefix(i)) |
| .append(':') |
| .append(reader.getAttributeLocalName(i)) |
| .append("=\"") |
| .append(uriAttrFlg ? relativeToAbsoluteUrl(reader.getAttributeValue(i), baseUrl) : reader.getAttributeValue(i)) |
| .append('"'); |
| if (!tmpNsSet.contains(reader.getAttributePrefix(i))) { |
| xmlnsCode |
| .append(" xmlns:") |
| .append(reader.getAttributePrefix(i)) |
| .append("=\"") |
| .append(reader.getAttributeNamespace(i)) |
| .append('"'); |
| tmpNsSet.add(reader.getAttributePrefix(i)); |
| } // end if prefix already processed |
| } |
| } // end foreach attr |
| elementCode |
| .append(xmlnsCode) // complete the start element tag |
| .append(attrCode) |
| .append('>'); |
| break; |
| //case XMLStreamConstants.ATTRIBUTE: Unreachable (I hope ;-) |
| // break; |
| //case XMLStreamConstants.NAMESPACE: Unreachable (I hope ;-) |
| // break; |
| case XMLStreamConstants.END_ELEMENT: |
| curName = reader.getName(); |
| if (elementName.equals(curName)) { // it is our element ! |
| depth--; // go up |
| } |
| elementCode |
| .append("</") // append appropriate XML code |
| .append("".equals(curName.getPrefix())?"":curName.getPrefix()+':') |
| .append(curName.getLocalPart()) |
| .append('>'); // complete the end element tag |
| break; |
| case XMLStreamConstants.CHARACTERS: |
| elementCode.append(reader.getText()); // append text data |
| break; |
| case XMLStreamConstants.CDATA: |
| elementCode |
| .append("<![CDATA[") // append CDATA delimiters |
| .append(reader.getText()) |
| .append("]]>"); |
| break; |
| case XMLStreamConstants.COMMENT: // Ignore any comments |
| break; |
| case XMLStreamConstants.SPACE: // Ignore spaces as well |
| break; |
| } |
| if (reader.hasNext() && depth>0) { |
| reader.next(); |
| } |
| } while (XMLStreamConstants.END_DOCUMENT!=reader.getEventType() && depth>0); |
| policyRec.policyModel = ModelUnmarshaller.getUnmarshaller().unmarshalModel( |
| new StringReader(elementCode.toString())); |
| if (null != policyRec.policyModel.getPolicyId()) { |
| policyRec.setUri(baseUrl + "#" + policyRec.policyModel.getPolicyId(), policyRec.policyModel.getPolicyId()); |
| } else if (policyRec.policyModel.getPolicyName() != null) { |
| policyRec.setUri(policyRec.policyModel.getPolicyName(), policyRec.policyModel.getPolicyName()); |
| } |
| } catch(Exception e) { |
| throw LOGGER.logSevereException(new WebServiceException(PolicyMessages.WSP_1013_EXCEPTION_WHEN_READING_POLICY_ELEMENT(elementCode.toString()), e)); |
| } |
| urlsRead.add(baseUrl); |
| return policyRec; |
| } |
| |
| |
| public Set<String> getUrlsRead() { |
| return this.urlsRead; |
| } |
| |
| |
| /** |
| * Reads policy reference element <wsp:PolicyReference/> and returns referenced policy URI as String |
| * |
| * @param reader The XMLStreamReader should be in START_ELEMENT state and point to the PolicyReference element. |
| * @return The URI contained in the PolicyReference |
| */ |
| public String readPolicyReferenceElement(final XMLStreamReader reader) { |
| try { |
| if (NamespaceVersion.resolveAsToken(reader.getName()) == XmlToken.PolicyReference) { // "PolicyReference" element interests me |
| for (int i = 0; i < reader.getAttributeCount(); i++) { |
| if (XmlToken.resolveToken(reader.getAttributeName(i).getLocalPart()) == XmlToken.Uri) { |
| final String uriValue = reader.getAttributeValue(i); |
| reader.next(); |
| return uriValue; |
| } |
| } |
| } |
| reader.next(); |
| return null; |
| } catch(XMLStreamException e) { |
| throw LOGGER.logSevereException(new WebServiceException(PolicyMessages.WSP_1001_XML_EXCEPTION_WHEN_PROCESSING_POLICY_REFERENCE(), e)); |
| } |
| } |
| |
| |
| /** |
| * Utility method to construct an absolute URL from a relative URI and a base URL. |
| * |
| * If the relativeUri already is an absolute URL, the method returns the relativeUri. |
| * |
| * @param relativeUri The relative URI |
| * @param baseUri The base URL |
| * @return The relative URI appended to the base URL. If relativeUri already is |
| * an absolute URL, the method returns the relativeUri. |
| */ |
| public static String relativeToAbsoluteUrl(final String relativeUri, final String baseUri) { |
| if ('#' != relativeUri.charAt(0)) { // TODO: escaped char could be an issue? |
| return relativeUri; // absolute already |
| } |
| return (null == baseUri) ? relativeUri : baseUri + relativeUri; |
| } |
| |
| } |