blob: 8f36da1bbd387aead32dc987ac635dfb9f215907 [file] [log] [blame]
/*
* 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;
}
}