package com.sun.xml.internal.ws.policy.sourcemodel;
import com.sun.xml.internal.ws.policy.PolicyConstants;
import com.sun.xml.internal.ws.policy.PolicyException;
import com.sun.xml.internal.ws.policy.privateutil.LocalizationMessages;
import com.sun.xml.internal.ws.policy.privateutil.PolicyLogger;
import com.sun.xml.internal.ws.policy.sourcemodel.wspolicy.NamespaceVersion;
import com.sun.xml.internal.ws.policy.sourcemodel.wspolicy.XmlToken;
import java.io.Reader;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
public class XmlPolicyModelUnmarshaller extends PolicyModelUnmarshaller {
private static final PolicyLogger LOGGER = PolicyLogger.getLogger(XmlPolicyModelUnmarshaller.class);
protected XmlPolicyModelUnmarshaller() {
}
public PolicySourceModel unmarshalModel(final Object storage) throws PolicyException {
final XMLEventReader reader = createXMLEventReader(storage);
PolicySourceModel model = null;
loop:
while (reader.hasNext()) {
try {
final XMLEvent event = reader.peek();
switch (event.getEventType()) {
case XMLStreamConstants.START_DOCUMENT:
case XMLStreamConstants.COMMENT:
reader.nextEvent();
break;
case XMLStreamConstants.CHARACTERS:
processCharacters(ModelNode.Type.POLICY, event.asCharacters(), null);
reader.nextEvent();
break;
case XMLStreamConstants.START_ELEMENT:
if (NamespaceVersion.resolveAsToken(event.asStartElement().getName()) == XmlToken.Policy) {
StartElement rootElement = reader.nextEvent().asStartElement();
model = initializeNewModel(rootElement);
unmarshalNodeContent(model.getNamespaceVersion(), model.getRootNode(), rootElement.getName(), reader);
break loop;
} else {
throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0048_POLICY_ELEMENT_EXPECTED_FIRST()));
}
default:
throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0048_POLICY_ELEMENT_EXPECTED_FIRST()));
}
} catch (XMLStreamException e) {
throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0068_FAILED_TO_UNMARSHALL_POLICY_EXPRESSION(), e));
}
}
return model;
}
protected PolicySourceModel createSourceModel(NamespaceVersion nsVersion, String id, String name) {
return PolicySourceModel.createPolicySourceModel(nsVersion, id, name);
}
private PolicySourceModel initializeNewModel(final StartElement element) throws PolicyException, XMLStreamException {
PolicySourceModel model;
final NamespaceVersion nsVersion = NamespaceVersion.resolveVersion(element.getName().getNamespaceURI());
final Attribute policyName = getAttributeByName(element, nsVersion.asQName(XmlToken.Name));
final Attribute xmlId = getAttributeByName(element, PolicyConstants.XML_ID);
Attribute policyId = getAttributeByName(element, PolicyConstants.WSU_ID);
if (policyId == null) {
policyId = xmlId;
} else if (xmlId != null) {
throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0058_MULTIPLE_POLICY_IDS_NOT_ALLOWED()));
}
model = createSourceModel(nsVersion,
(policyId == null) ? null : policyId.getValue(),
(policyName == null) ? null : policyName.getValue());
return model;
}
private ModelNode addNewChildNode(final NamespaceVersion nsVersion, final ModelNode parentNode, final StartElement childElement) throws PolicyException {
ModelNode childNode;
final QName childElementName = childElement.getName();
if (parentNode.getType() == ModelNode.Type.ASSERTION_PARAMETER_NODE) {
childNode = parentNode.createChildAssertionParameterNode();
} else {
XmlToken token = NamespaceVersion.resolveAsToken(childElementName);
switch (token) {
case Policy:
childNode = parentNode.createChildPolicyNode();
break;
case All:
childNode = parentNode.createChildAllNode();
break;
case ExactlyOne:
childNode = parentNode.createChildExactlyOneNode();
break;
case PolicyReference:
final Attribute uri = getAttributeByName(childElement, nsVersion.asQName(XmlToken.Uri));
if (uri == null) {
throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0040_POLICY_REFERENCE_URI_ATTR_NOT_FOUND()));
} else {
try {
final URI reference = new URI(uri.getValue());
final Attribute digest = getAttributeByName(childElement, nsVersion.asQName(XmlToken.Digest));
PolicyReferenceData refData;
if (digest == null) {
refData = new PolicyReferenceData(reference);
} else {
final Attribute digestAlgorithm = getAttributeByName(childElement, nsVersion.asQName(XmlToken.DigestAlgorithm));
URI algorithmRef = null;
if (digestAlgorithm != null) {
algorithmRef = new URI(digestAlgorithm.getValue());
}
refData = new PolicyReferenceData(reference, digest.getValue(), algorithmRef);
}
childNode = parentNode.createChildPolicyReferenceNode(refData);
} catch (URISyntaxException e) {
throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0012_UNABLE_TO_UNMARSHALL_POLICY_MALFORMED_URI(), e));
}
}
break;
default:
if (parentNode.isDomainSpecific()) {
childNode = parentNode.createChildAssertionParameterNode();
} else {
childNode = parentNode.createChildAssertionNode();
}
}
}
return childNode;
}
private void parseAssertionData(NamespaceVersion nsVersion, String value, ModelNode childNode, final StartElement childElement) throws IllegalArgumentException, PolicyException {
final Map<QName, String> attributeMap = new HashMap<QName, String>();
boolean optional = false;
boolean ignorable = false;
final Iterator iterator = childElement.getAttributes();
while (iterator.hasNext()) {
final Attribute nextAttribute = (Attribute) iterator.next();
final QName name = nextAttribute.getName();
if (attributeMap.containsKey(name)) {
throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0059_MULTIPLE_ATTRS_WITH_SAME_NAME_DETECTED_FOR_ASSERTION(nextAttribute.getName(), childElement.getName())));
} else {
if (nsVersion.asQName(XmlToken.Optional).equals(name)) {
optional = parseBooleanValue(nextAttribute.getValue());
} else if (nsVersion.asQName(XmlToken.Ignorable).equals(name)) {
ignorable = parseBooleanValue(nextAttribute.getValue());
} else {
attributeMap.put(name, nextAttribute.getValue());
}
}
}
final AssertionData nodeData = new AssertionData(childElement.getName(), value, attributeMap, childNode.getType(), optional, ignorable);
if (nodeData.containsAttribute(PolicyConstants.VISIBILITY_ATTRIBUTE)) {
final String visibilityValue = nodeData.getAttributeValue(PolicyConstants.VISIBILITY_ATTRIBUTE);
if (!PolicyConstants.VISIBILITY_VALUE_PRIVATE.equals(visibilityValue)) {
throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0004_UNEXPECTED_VISIBILITY_ATTR_VALUE(visibilityValue)));
}
}
childNode.setOrReplaceNodeData(nodeData);
}
private Attribute getAttributeByName(final StartElement element,
final QName attributeName) {
Attribute attribute = element.getAttributeByName(attributeName);
if (attribute == null) {
final String localAttributeName = attributeName.getLocalPart();
final Iterator iterator = element.getAttributes();
while (iterator.hasNext()) {
final Attribute nextAttribute = (Attribute) iterator.next();
final QName aName = nextAttribute.getName();
final boolean attributeFoundByWorkaround = aName.equals(attributeName) || (aName.getLocalPart().equals(localAttributeName) && (aName.getPrefix() == null || "".equals(aName.getPrefix())));
if (attributeFoundByWorkaround) {
attribute = nextAttribute;
break;
}
}
}
return attribute;
}
private String unmarshalNodeContent(final NamespaceVersion nsVersion, final ModelNode node, final QName nodeElementName, final XMLEventReader reader) throws PolicyException {
StringBuilder valueBuffer = null;
loop:
while (reader.hasNext()) {
try {
final XMLEvent xmlParserEvent = reader.nextEvent();
switch (xmlParserEvent.getEventType()) {
case XMLStreamConstants.COMMENT:
break;
case XMLStreamConstants.CHARACTERS:
valueBuffer = processCharacters(node.getType(), xmlParserEvent.asCharacters(), valueBuffer);
break;
case XMLStreamConstants.END_ELEMENT:
checkEndTagName(nodeElementName, xmlParserEvent.asEndElement());
break loop;
case XMLStreamConstants.START_ELEMENT:
final StartElement childElement = xmlParserEvent.asStartElement();
ModelNode childNode = addNewChildNode(nsVersion, node, childElement);
String value = unmarshalNodeContent(nsVersion, childNode, childElement.getName(), reader);
if (childNode.isDomainSpecific()) {
parseAssertionData(nsVersion, value, childNode, childElement);
}
break;
default:
throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0011_UNABLE_TO_UNMARSHALL_POLICY_XML_ELEM_EXPECTED()));
}
} catch (XMLStreamException e) {
throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0068_FAILED_TO_UNMARSHALL_POLICY_EXPRESSION(), e));
}
}
return (valueBuffer == null) ? null : valueBuffer.toString().trim();
}
private XMLEventReader createXMLEventReader(final Object storage)
throws PolicyException {
if (storage instanceof XMLEventReader) {
return (XMLEventReader) storage;
}
else if (!(storage instanceof Reader)) {
throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0022_STORAGE_TYPE_NOT_SUPPORTED(storage.getClass().getName())));
}
try {
return XMLInputFactory.newInstance().createXMLEventReader((Reader) storage);
} catch (XMLStreamException e) {
throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0014_UNABLE_TO_INSTANTIATE_READER_FOR_STORAGE(), e));
}
}
private void checkEndTagName(final QName expected, final EndElement element) throws PolicyException {
final QName actual = element.getName();
if (!expected.equals(actual)) {
throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0003_UNMARSHALLING_FAILED_END_TAG_DOES_NOT_MATCH(expected, actual)));
}
}
private StringBuilder processCharacters(final ModelNode.Type currentNodeType, final Characters characters,
final StringBuilder currentValueBuffer)
throws PolicyException {
if (characters.isWhiteSpace()) {
return currentValueBuffer;
} else {
final StringBuilder buffer = (currentValueBuffer == null) ? new StringBuilder() : currentValueBuffer;
final String data = characters.getData();
if (currentNodeType == ModelNode.Type.ASSERTION || currentNodeType == ModelNode.Type.ASSERTION_PARAMETER_NODE) {
return buffer.append(data);
} else {
throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0009_UNEXPECTED_CDATA_ON_SOURCE_MODEL_NODE(currentNodeType, data)));
}
}
}
private boolean parseBooleanValue(String value) throws PolicyException {
if ("true".equals(value) || "1".equals(value)) {
return true;
}
else if ("false".equals(value) || "0".equals(value)) {
return false;
}
throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0095_INVALID_BOOLEAN_VALUE(value)));
}
}