Thu, 12 Oct 2017 19:44:07 +0800
merge
1 /*
2 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package com.sun.xml.internal.ws.policy.sourcemodel;
28 import com.sun.xml.internal.ws.policy.PolicyConstants;
29 import com.sun.xml.internal.ws.policy.PolicyException;
30 import com.sun.xml.internal.ws.policy.privateutil.LocalizationMessages;
31 import com.sun.xml.internal.ws.policy.privateutil.PolicyLogger;
32 import com.sun.xml.internal.ws.policy.sourcemodel.wspolicy.NamespaceVersion;
33 import com.sun.xml.internal.ws.policy.sourcemodel.wspolicy.XmlToken;
35 import java.io.Reader;
36 import java.net.URI;
37 import java.net.URISyntaxException;
38 import java.util.HashMap;
39 import java.util.Iterator;
40 import java.util.Map;
41 import javax.xml.namespace.QName;
42 import javax.xml.stream.XMLEventReader;
43 import javax.xml.stream.XMLInputFactory;
44 import javax.xml.stream.XMLStreamConstants;
45 import javax.xml.stream.XMLStreamException;
46 import javax.xml.stream.events.Attribute;
47 import javax.xml.stream.events.Characters;
48 import javax.xml.stream.events.EndElement;
49 import javax.xml.stream.events.StartElement;
50 import javax.xml.stream.events.XMLEvent;
52 /**
53 * Unmarshal XML policy expressions.
54 *
55 * @author Marek Potociar
56 * @author Fabian Ritzmann
57 */
58 public class XmlPolicyModelUnmarshaller extends PolicyModelUnmarshaller {
60 private static final PolicyLogger LOGGER = PolicyLogger.getLogger(XmlPolicyModelUnmarshaller.class);
62 /**
63 * Creates a new instance of XmlPolicyModelUnmarshaller
64 */
65 protected XmlPolicyModelUnmarshaller() {
66 // nothing to initialize
67 }
69 /**
70 * See {@link PolicyModelUnmarshaller#unmarshalModel(Object) base method documentation}.
71 */
72 public PolicySourceModel unmarshalModel(final Object storage) throws PolicyException {
73 final XMLEventReader reader = createXMLEventReader(storage);
74 PolicySourceModel model = null;
76 loop:
77 while (reader.hasNext()) {
78 try {
79 final XMLEvent event = reader.peek();
80 switch (event.getEventType()) {
81 case XMLStreamConstants.START_DOCUMENT:
82 case XMLStreamConstants.COMMENT:
83 reader.nextEvent();
84 break; // skipping the comments and start document events
85 case XMLStreamConstants.CHARACTERS:
86 processCharacters(ModelNode.Type.POLICY, event.asCharacters(), null);
87 // we advance the reader only if there is no exception thrown from
88 // the processCharacters(...) call. Otherwise we don't modify the stream
89 reader.nextEvent();
90 break;
91 case XMLStreamConstants.START_ELEMENT:
92 if (NamespaceVersion.resolveAsToken(event.asStartElement().getName()) == XmlToken.Policy) {
93 StartElement rootElement = reader.nextEvent().asStartElement();
95 model = initializeNewModel(rootElement);
96 unmarshalNodeContent(model.getNamespaceVersion(), model.getRootNode(), rootElement.getName(), reader);
98 break loop;
99 } else {
100 throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0048_POLICY_ELEMENT_EXPECTED_FIRST()));
101 }
102 default:
103 throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0048_POLICY_ELEMENT_EXPECTED_FIRST()));
104 }
105 } catch (XMLStreamException e) {
106 throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0068_FAILED_TO_UNMARSHALL_POLICY_EXPRESSION(), e));
107 }
108 }
109 return model;
110 }
112 /**
113 * Allow derived classes to pass in a custom instance of PolicySourceModel.
114 *
115 * @param nsVersion
116 * @param id
117 * @param name
118 * @return
119 */
120 protected PolicySourceModel createSourceModel(NamespaceVersion nsVersion, String id, String name) {
121 return PolicySourceModel.createPolicySourceModel(nsVersion, id, name);
122 }
124 private PolicySourceModel initializeNewModel(final StartElement element) throws PolicyException, XMLStreamException {
125 PolicySourceModel model;
127 final NamespaceVersion nsVersion = NamespaceVersion.resolveVersion(element.getName().getNamespaceURI());
129 final Attribute policyName = getAttributeByName(element, nsVersion.asQName(XmlToken.Name));
130 final Attribute xmlId = getAttributeByName(element, PolicyConstants.XML_ID);
131 Attribute policyId = getAttributeByName(element, PolicyConstants.WSU_ID);
133 if (policyId == null) {
134 policyId = xmlId;
135 } else if (xmlId != null) {
136 throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0058_MULTIPLE_POLICY_IDS_NOT_ALLOWED()));
137 }
139 model = createSourceModel(nsVersion,
140 (policyId == null) ? null : policyId.getValue(),
141 (policyName == null) ? null : policyName.getValue());
143 return model;
144 }
146 private ModelNode addNewChildNode(final NamespaceVersion nsVersion, final ModelNode parentNode, final StartElement childElement) throws PolicyException {
147 ModelNode childNode;
148 final QName childElementName = childElement.getName();
149 if (parentNode.getType() == ModelNode.Type.ASSERTION_PARAMETER_NODE) {
150 childNode = parentNode.createChildAssertionParameterNode();
151 } else {
152 XmlToken token = NamespaceVersion.resolveAsToken(childElementName);
154 switch (token) {
155 case Policy:
156 childNode = parentNode.createChildPolicyNode();
157 break;
158 case All:
159 childNode = parentNode.createChildAllNode();
160 break;
161 case ExactlyOne:
162 childNode = parentNode.createChildExactlyOneNode();
163 break;
164 case PolicyReference:
165 final Attribute uri = getAttributeByName(childElement, nsVersion.asQName(XmlToken.Uri));
166 if (uri == null) {
167 throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0040_POLICY_REFERENCE_URI_ATTR_NOT_FOUND()));
168 } else {
169 try {
170 final URI reference = new URI(uri.getValue());
171 final Attribute digest = getAttributeByName(childElement, nsVersion.asQName(XmlToken.Digest));
172 PolicyReferenceData refData;
173 if (digest == null) {
174 refData = new PolicyReferenceData(reference);
175 } else {
176 final Attribute digestAlgorithm = getAttributeByName(childElement, nsVersion.asQName(XmlToken.DigestAlgorithm));
177 URI algorithmRef = null;
178 if (digestAlgorithm != null) {
179 algorithmRef = new URI(digestAlgorithm.getValue());
180 }
181 refData = new PolicyReferenceData(reference, digest.getValue(), algorithmRef);
182 }
183 childNode = parentNode.createChildPolicyReferenceNode(refData);
184 } catch (URISyntaxException e) {
185 throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0012_UNABLE_TO_UNMARSHALL_POLICY_MALFORMED_URI(), e));
186 }
187 }
188 break;
189 default:
190 if (parentNode.isDomainSpecific()) {
191 childNode = parentNode.createChildAssertionParameterNode();
192 } else {
193 childNode = parentNode.createChildAssertionNode();
194 }
195 }
196 }
198 return childNode;
199 }
201 private void parseAssertionData(NamespaceVersion nsVersion, String value, ModelNode childNode, final StartElement childElement) throws IllegalArgumentException, PolicyException {
202 // finish assertion node processing: create and set assertion data...
203 final Map<QName, String> attributeMap = new HashMap<QName, String>();
204 boolean optional = false;
205 boolean ignorable = false;
207 final Iterator iterator = childElement.getAttributes();
208 while (iterator.hasNext()) {
209 final Attribute nextAttribute = (Attribute) iterator.next();
210 final QName name = nextAttribute.getName();
211 if (attributeMap.containsKey(name)) {
212 throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0059_MULTIPLE_ATTRS_WITH_SAME_NAME_DETECTED_FOR_ASSERTION(nextAttribute.getName(), childElement.getName())));
213 } else {
214 if (nsVersion.asQName(XmlToken.Optional).equals(name)) {
215 optional = parseBooleanValue(nextAttribute.getValue());
216 } else if (nsVersion.asQName(XmlToken.Ignorable).equals(name)) {
217 ignorable = parseBooleanValue(nextAttribute.getValue());
218 } else {
219 attributeMap.put(name, nextAttribute.getValue());
220 }
221 }
222 }
223 final AssertionData nodeData = new AssertionData(childElement.getName(), value, attributeMap, childNode.getType(), optional, ignorable);
225 // check visibility value syntax if present...
226 if (nodeData.containsAttribute(PolicyConstants.VISIBILITY_ATTRIBUTE)) {
227 final String visibilityValue = nodeData.getAttributeValue(PolicyConstants.VISIBILITY_ATTRIBUTE);
228 if (!PolicyConstants.VISIBILITY_VALUE_PRIVATE.equals(visibilityValue)) {
229 throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0004_UNEXPECTED_VISIBILITY_ATTR_VALUE(visibilityValue)));
230 }
231 }
233 childNode.setOrReplaceNodeData(nodeData);
234 }
236 private Attribute getAttributeByName(final StartElement element,
237 final QName attributeName) {
238 // call standard API method to retrieve the attribute by name
239 Attribute attribute = element.getAttributeByName(attributeName);
241 // try to find the attribute without a prefix.
242 if (attribute == null) {
243 final String localAttributeName = attributeName.getLocalPart();
244 final Iterator iterator = element.getAttributes();
245 while (iterator.hasNext()) {
246 final Attribute nextAttribute = (Attribute) iterator.next();
247 final QName aName = nextAttribute.getName();
248 final boolean attributeFoundByWorkaround = aName.equals(attributeName) || (aName.getLocalPart().equals(localAttributeName) && (aName.getPrefix() == null || "".equals(aName.getPrefix())));
249 if (attributeFoundByWorkaround) {
250 attribute = nextAttribute;
251 break;
252 }
254 }
255 }
257 return attribute;
258 }
260 private String unmarshalNodeContent(final NamespaceVersion nsVersion, final ModelNode node, final QName nodeElementName, final XMLEventReader reader) throws PolicyException {
261 StringBuilder valueBuffer = null;
263 loop:
264 while (reader.hasNext()) {
265 try {
266 final XMLEvent xmlParserEvent = reader.nextEvent();
267 switch (xmlParserEvent.getEventType()) {
268 case XMLStreamConstants.COMMENT:
269 break; // skipping the comments
270 case XMLStreamConstants.CHARACTERS:
271 valueBuffer = processCharacters(node.getType(), xmlParserEvent.asCharacters(), valueBuffer);
272 break;
273 case XMLStreamConstants.END_ELEMENT:
274 checkEndTagName(nodeElementName, xmlParserEvent.asEndElement());
275 break loop; // data exctraction for currently processed policy node is done
276 case XMLStreamConstants.START_ELEMENT:
277 final StartElement childElement = xmlParserEvent.asStartElement();
279 ModelNode childNode = addNewChildNode(nsVersion, node, childElement);
280 String value = unmarshalNodeContent(nsVersion, childNode, childElement.getName(), reader);
282 if (childNode.isDomainSpecific()) {
283 parseAssertionData(nsVersion, value, childNode, childElement);
284 }
285 break;
286 default:
287 throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0011_UNABLE_TO_UNMARSHALL_POLICY_XML_ELEM_EXPECTED()));
288 }
289 } catch (XMLStreamException e) {
290 throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0068_FAILED_TO_UNMARSHALL_POLICY_EXPRESSION(), e));
291 }
292 }
294 return (valueBuffer == null) ? null : valueBuffer.toString().trim();
295 }
297 /**
298 * Method checks if the storage type is supported and transforms it to XMLEventReader instance which is then returned.
299 * Throws PolicyException if the transformation is not succesfull or if the storage type is not supported.
300 *
301 * @param storage An XMLEventReader instance.
302 * @return The storage cast to an XMLEventReader.
303 * @throws PolicyException If the XMLEventReader cast failed.
304 */
305 private XMLEventReader createXMLEventReader(final Object storage)
306 throws PolicyException {
307 if (storage instanceof XMLEventReader) {
308 return (XMLEventReader) storage;
309 }
310 else if (!(storage instanceof Reader)) {
311 throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0022_STORAGE_TYPE_NOT_SUPPORTED(storage.getClass().getName())));
312 }
314 try {
315 return XMLInputFactory.newInstance().createXMLEventReader((Reader) storage);
316 } catch (XMLStreamException e) {
317 throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0014_UNABLE_TO_INSTANTIATE_READER_FOR_STORAGE(), e));
318 }
320 }
322 /**
323 * Method checks whether the actual name of the end tag is equal to the expected name - the name of currently unmarshalled
324 * XML policy model element. Throws exception, if the two FQNs are not equal as expected.
325 *
326 * @param expected The expected element name.
327 * @param element The actual element.
328 * @throws PolicyException If the actual element name did not match the expected element.
329 */
330 private void checkEndTagName(final QName expected, final EndElement element) throws PolicyException {
331 final QName actual = element.getName();
332 if (!expected.equals(actual)) {
333 throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0003_UNMARSHALLING_FAILED_END_TAG_DOES_NOT_MATCH(expected, actual)));
334 }
336 }
338 private StringBuilder processCharacters(final ModelNode.Type currentNodeType, final Characters characters,
339 final StringBuilder currentValueBuffer)
340 throws PolicyException {
341 if (characters.isWhiteSpace()) {
342 return currentValueBuffer;
343 } else {
344 final StringBuilder buffer = (currentValueBuffer == null) ? new StringBuilder() : currentValueBuffer;
345 final String data = characters.getData();
346 if (currentNodeType == ModelNode.Type.ASSERTION || currentNodeType == ModelNode.Type.ASSERTION_PARAMETER_NODE) {
347 return buffer.append(data);
348 } else {
349 throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0009_UNEXPECTED_CDATA_ON_SOURCE_MODEL_NODE(currentNodeType, data)));
350 }
352 }
353 }
355 /**
356 * Return true if the value is "true" or "1". Return false if the value is
357 * "false" or "0". Throw an exception otherwise. The test is case sensitive.
358 *
359 * @param value The String representation of the value. Must not be null.
360 * @return True if the value is "true" or "1". False if the value is
361 * "false" or "0".
362 * @throws PolicyException If the value is not "true", "false", "0" or "1".
363 */
364 private boolean parseBooleanValue(String value) throws PolicyException {
365 if ("true".equals(value) || "1".equals(value)) {
366 return true;
367 }
368 else if ("false".equals(value) || "0".equals(value)) {
369 return false;
370 }
371 throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0095_INVALID_BOOLEAN_VALUE(value)));
372 }
374 }