aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraefimov <none@none>2017-01-12 00:25:07 +0300
committeraefimov <none@none>2017-01-12 00:25:07 +0300
commita60b599ac0fb611f3d51dc2a905195b65429b8cc (patch)
treed78cfa42a9615fb8ad368390e98536fca4c92fed
parent34e2b825ad9719420a5bedf6bf9d323d23bf4697 (diff)
downloadjdk8u_jaxws-a60b599ac0fb611f3d51dc2a905195b65429b8cc.tar.gz
Reviewed-by: lancea, coffeys
-rw-r--r--src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/DetailImpl.java30
-rw-r--r--src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.java33
-rw-r--r--src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SaajStaxWriter.java314
3 files changed, 284 insertions, 93 deletions
diff --git a/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/DetailImpl.java b/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/DetailImpl.java
index 034629e8..bd6727f0 100644
--- a/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/DetailImpl.java
+++ b/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/DetailImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -47,13 +47,13 @@ public abstract class DetailImpl extends FaultElementImpl implements Detail {
public DetailEntry addDetailEntry(Name name) throws SOAPException {
DetailEntry entry = createDetailEntry(name);
addNode(entry);
- return (DetailEntry) circumventBug5034339(entry);
+ return entry;
}
public DetailEntry addDetailEntry(QName qname) throws SOAPException {
DetailEntry entry = createDetailEntry(qname);
addNode(entry);
- return (DetailEntry) circumventBug5034339(entry);
+ return entry;
}
protected SOAPElement addElement(Name name) throws SOAPException {
@@ -119,28 +119,4 @@ public abstract class DetailImpl extends FaultElementImpl implements Detail {
return true;
}
- //overriding this method since the only two uses of this method
- // are in ElementImpl and DetailImpl
- //whereas the original base impl does the correct job for calls to it inside ElementImpl
- // But it would not work for DetailImpl.
- protected SOAPElement circumventBug5034339(SOAPElement element) {
-
- Name elementName = element.getElementName();
- if (!isNamespaceQualified(elementName)) {
- String prefix = elementName.getPrefix();
- String defaultNamespace = getNamespaceURI(prefix);
- if (defaultNamespace != null) {
- Name newElementName =
- NameImpl.create(
- elementName.getLocalName(),
- elementName.getPrefix(),
- defaultNamespace);
- SOAPElement newElement = createDetailEntry(newElementName);
- replaceChild(newElement, element);
- return newElement;
- }
- }
- return element;
- }
-
}
diff --git a/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.java b/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.java
index fc2dcfee..6b833370 100644
--- a/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.java
+++ b/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -127,8 +127,11 @@ public class ElementImpl
}
public SOAPElement addChildElement(String localName) throws SOAPException {
- return (SOAPElement) addChildElement(
- NameImpl.createFromUnqualifiedName(localName));
+ String nsUri = getNamespaceURI("");
+ Name name = (nsUri == null || nsUri.isEmpty())
+ ? NameImpl.createFromUnqualifiedName(localName)
+ : NameImpl.createFromQualifiedName(localName, nsUri);
+ return addChildElement(name);
}
public SOAPElement addChildElement(String localName, String prefix)
@@ -372,13 +375,13 @@ public class ElementImpl
protected SOAPElement addElement(Name name) throws SOAPException {
SOAPElement newElement = createElement(name);
addNode(newElement);
- return circumventBug5034339(newElement);
+ return newElement;
}
protected SOAPElement addElement(QName name) throws SOAPException {
SOAPElement newElement = createElement(name);
addNode(newElement);
- return circumventBug5034339(newElement);
+ return newElement;
}
protected SOAPElement createElement(Name name) {
@@ -1201,26 +1204,6 @@ public class ElementImpl
return !"".equals(name.getNamespaceURI());
}
- protected SOAPElement circumventBug5034339(SOAPElement element) {
-
- Name elementName = element.getElementName();
- if (!isNamespaceQualified(elementName)) {
- String prefix = elementName.getPrefix();
- String defaultNamespace = getNamespaceURI(prefix);
- if (defaultNamespace != null) {
- Name newElementName =
- NameImpl.create(
- elementName.getLocalName(),
- elementName.getPrefix(),
- defaultNamespace);
- SOAPElement newElement = createElement(newElementName);
- replaceChild(newElement, element);
- return newElement;
- }
- }
- return element;
- }
-
//TODO: This is a temporary SAAJ workaround for optimizing XWS
// should be removed once the corresponding JAXP bug is fixed
// It appears the bug will be fixed in JAXP 1.4 (not by Appserver 9 timeframe)
diff --git a/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SaajStaxWriter.java b/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SaajStaxWriter.java
index 6414593f..f1ed6979 100644
--- a/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SaajStaxWriter.java
+++ b/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SaajStaxWriter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, 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
@@ -25,8 +25,10 @@
package com.sun.xml.internal.ws.api.message.saaj;
-import java.util.Arrays;
import java.util.Iterator;
+import java.util.Arrays;
+import java.util.List;
+import java.util.LinkedList;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
@@ -42,6 +44,17 @@ import org.w3c.dom.Node;
/**
* SaajStaxWriter builds a SAAJ SOAPMessage by using XMLStreamWriter interface.
*
+ * <p>
+ * Defers creation of SOAPElement until all the aspects of the name of the element are known.
+ * In some cases, the namespace uri is indicated only by the {@link #writeNamespace(String, String)} call.
+ * After opening an element ({@code writeStartElement}, {@code writeEmptyElement} methods), all attributes
+ * and namespace assignments are retained within {@link DeferredElement} object ({@code deferredElement} field).
+ * As soon as any other method than {@code writeAttribute}, {@code writeNamespace}, {@code writeDefaultNamespace}
+ * or {@code setNamespace} is called, the contents of {@code deferredElement} is transformed into new SOAPElement
+ * (which is appropriately inserted into the SOAPMessage under construction).
+ * This mechanism is necessary to fix JDK-8159058 issue.
+ * </p>
+ *
* @author shih-chang.chen@oracle.com
*/
public class SaajStaxWriter implements XMLStreamWriter {
@@ -49,6 +62,7 @@ public class SaajStaxWriter implements XMLStreamWriter {
protected SOAPMessage soap;
protected String envURI;
protected SOAPElement currentElement;
+ protected DeferredElement deferredElement;
static final protected String Envelope = "Envelope";
static final protected String Header = "Header";
@@ -59,6 +73,7 @@ public class SaajStaxWriter implements XMLStreamWriter {
soap = msg;
currentElement = soap.getSOAPPart().getEnvelope();
envURI = currentElement.getNamespaceURI();
+ this.deferredElement = new DeferredElement();
}
public SOAPMessage getSOAPMessage() {
@@ -67,11 +82,8 @@ public class SaajStaxWriter implements XMLStreamWriter {
@Override
public void writeStartElement(final String localName) throws XMLStreamException {
- try {
- currentElement = currentElement.addChildElement(localName);
- } catch (SOAPException e) {
- throw new XMLStreamException(e);
- }
+ currentElement = deferredElement.flushTo(currentElement);
+ deferredElement.setLocalName(localName);
}
@Override
@@ -81,8 +93,10 @@ public class SaajStaxWriter implements XMLStreamWriter {
@Override
public void writeStartElement(final String prefix, final String ln, final String ns) throws XMLStreamException {
- try {
- if (envURI.equals(ns)) {
+ currentElement = deferredElement.flushTo(currentElement);
+
+ if (envURI.equals(ns)) {
+ try {
if (Envelope.equals(ln)) {
currentElement = soap.getSOAPPart().getEnvelope();
fixPrefix(prefix);
@@ -96,13 +110,16 @@ public class SaajStaxWriter implements XMLStreamWriter {
fixPrefix(prefix);
return;
}
+ } catch (SOAPException e) {
+ throw new XMLStreamException(e);
}
- currentElement = (prefix == null) ?
- currentElement.addChildElement(new QName(ns, ln)) :
- currentElement.addChildElement(ln, prefix, ns);
- } catch (SOAPException e) {
- throw new XMLStreamException(e);
+
}
+
+ deferredElement.setLocalName(ln);
+ deferredElement.setNamespaceUri(ns);
+ deferredElement.setPrefix(prefix);
+
}
private void fixPrefix(final String prfx) throws XMLStreamException {
@@ -129,11 +146,13 @@ public class SaajStaxWriter implements XMLStreamWriter {
@Override
public void writeEndElement() throws XMLStreamException {
+ currentElement = deferredElement.flushTo(currentElement);
if (currentElement != null) currentElement = currentElement.getParentElement();
}
@Override
public void writeEndDocument() throws XMLStreamException {
+ currentElement = deferredElement.flushTo(currentElement);
}
@Override
@@ -151,19 +170,14 @@ public class SaajStaxWriter implements XMLStreamWriter {
@Override
public void writeAttribute(final String prefix, final String ns, final String ln, final String value) throws XMLStreamException {
- try {
- if (ns == null) {
- if (prefix == null && xmlns.equals(ln)) {
- currentElement.addNamespaceDeclaration("", value);
- } else {
- currentElement.setAttributeNS("", ln, value);
- }
+ if (ns == null && prefix == null && xmlns.equals(ln)) {
+ writeNamespace("", value);
+ } else {
+ if (deferredElement.isInitialized()) {
+ deferredElement.addAttribute(prefix, ns, ln, value);
} else {
- QName name = (prefix == null) ? new QName(ns, ln) : new QName(ns, ln, prefix);
- currentElement.addAttribute(name, value);
+ addAttibuteToElement(currentElement, prefix, ns, ln, value);
}
- } catch (SOAPException e) {
- throw new XMLStreamException(e);
}
}
@@ -174,16 +188,16 @@ public class SaajStaxWriter implements XMLStreamWriter {
@Override
public void writeNamespace(String prefix, final String uri) throws XMLStreamException {
-
// make prefix default if null or "xmlns" (according to javadoc)
- if (prefix == null || "xmlns".equals(prefix)) {
- prefix = "";
- }
-
- try {
- currentElement.addNamespaceDeclaration(prefix, uri);
- } catch (SOAPException e) {
- throw new XMLStreamException(e);
+ String thePrefix = prefix == null || "xmlns".equals(prefix) ? "" : prefix;
+ if (deferredElement.isInitialized()) {
+ deferredElement.addNamespaceDeclaration(thePrefix, uri);
+ } else {
+ try {
+ currentElement.addNamespaceDeclaration(thePrefix, uri);
+ } catch (SOAPException e) {
+ throw new XMLStreamException(e);
+ }
}
}
@@ -194,35 +208,40 @@ public class SaajStaxWriter implements XMLStreamWriter {
@Override
public void writeComment(final String data) throws XMLStreamException {
+ currentElement = deferredElement.flushTo(currentElement);
Comment c = soap.getSOAPPart().createComment(data);
currentElement.appendChild(c);
}
@Override
public void writeProcessingInstruction(final String target) throws XMLStreamException {
+ currentElement = deferredElement.flushTo(currentElement);
Node n = soap.getSOAPPart().createProcessingInstruction(target, "");
currentElement.appendChild(n);
}
@Override
public void writeProcessingInstruction(final String target, final String data) throws XMLStreamException {
+ currentElement = deferredElement.flushTo(currentElement);
Node n = soap.getSOAPPart().createProcessingInstruction(target, data);
currentElement.appendChild(n);
}
@Override
public void writeCData(final String data) throws XMLStreamException {
+ currentElement = deferredElement.flushTo(currentElement);
Node n = soap.getSOAPPart().createCDATASection(data);
currentElement.appendChild(n);
}
@Override
public void writeDTD(final String dtd) throws XMLStreamException {
- //TODO ... Don't do anything here
+ currentElement = deferredElement.flushTo(currentElement);
}
@Override
public void writeEntityRef(final String name) throws XMLStreamException {
+ currentElement = deferredElement.flushTo(currentElement);
Node n = soap.getSOAPPart().createEntityReference(name);
currentElement.appendChild(n);
}
@@ -250,6 +269,7 @@ public class SaajStaxWriter implements XMLStreamWriter {
@Override
public void writeCharacters(final String text) throws XMLStreamException {
+ currentElement = deferredElement.flushTo(currentElement);
try {
currentElement.addTextNode(text);
} catch (SOAPException e) {
@@ -259,6 +279,7 @@ public class SaajStaxWriter implements XMLStreamWriter {
@Override
public void writeCharacters(final char[] text, final int start, final int len) throws XMLStreamException {
+ currentElement = deferredElement.flushTo(currentElement);
char[] chr = (start == 0 && len == text.length) ? text : Arrays.copyOfRange(text, start, start + len);
try {
currentElement.addTextNode(new String(chr));
@@ -274,10 +295,16 @@ public class SaajStaxWriter implements XMLStreamWriter {
@Override
public void setPrefix(final String prefix, final String uri) throws XMLStreamException {
- try {
- this.currentElement.addNamespaceDeclaration(prefix, uri);
- } catch (SOAPException e) {
- throw new XMLStreamException(e);
+ // TODO: this in fact is not what would be expected from XMLStreamWriter
+ // (e.g. XMLStreamWriter for writing to output stream does not write anything as result of
+ // this method, it just rememebers that given prefix is associated with the given uri
+ // for the scope; to actually declare the prefix assignment in the resulting XML, one
+ // needs to call writeNamespace(...) method
+ // Kept for backwards compatibility reasons - this might be worth of further investigation.
+ if (deferredElement.isInitialized()) {
+ deferredElement.addNamespaceDeclaration(prefix, uri);
+ } else {
+ throw new XMLStreamException("Namespace not associated with any element");
}
}
@@ -308,12 +335,12 @@ public class SaajStaxWriter implements XMLStreamWriter {
return currentElement.lookupPrefix(namespaceURI);
}
public Iterator getPrefixes(final String namespaceURI) {
- return new Iterator() {
+ return new Iterator<String>() {
String prefix = getPrefix(namespaceURI);
public boolean hasNext() {
return (prefix != null);
}
- public Object next() {
+ public String next() {
if (!hasNext()) throw new java.util.NoSuchElementException();
String next = prefix;
prefix = null;
@@ -324,4 +351,209 @@ public class SaajStaxWriter implements XMLStreamWriter {
}
};
}
+
+ static void addAttibuteToElement(SOAPElement element, String prefix, String ns, String ln, String value)
+ throws XMLStreamException {
+ try {
+ if (ns == null) {
+ element.setAttributeNS("", ln, value);
+ } else {
+ QName name = prefix == null ? new QName(ns, ln) : new QName(ns, ln, prefix);
+ element.addAttribute(name, value);
+ }
+ } catch (SOAPException e) {
+ throw new XMLStreamException(e);
+ }
+ }
+
+ /**
+ * Holds details of element that needs to be deferred in order to manage namespace assignments correctly.
+ *
+ * <p>
+ * An instance of can be set with all the aspects of the element name (local name, prefix, namespace uri).
+ * Attributes and namespace declarations (special case of attribute) can be added.
+ * Namespace declarations are handled so that the element namespace is updated if it is implied by the namespace
+ * declaration and the namespace was not set to non-{@code null} value previously.
+ * </p>
+ *
+ * <p>
+ * The state of this object can be {@link #flushTo(SOAPElement) flushed} to SOAPElement - new SOAPElement will
+ * be added a child element; the new element will have exactly the shape as represented by the state of this
+ * object. Note that the {@link #flushTo(SOAPElement)} method does nothing
+ * (and returns the argument immediately) if the state of this object is not initialized
+ * (i.e. local name is null).
+ * </p>
+ *
+ * @author ondrej.cerny@oracle.com
+ */
+ static class DeferredElement {
+ private String prefix;
+ private String localName;
+ private String namespaceUri;
+ private final List<NamespaceDeclaration> namespaceDeclarations;
+ private final List<AttributeDeclaration> attributeDeclarations;
+
+ DeferredElement() {
+ this.namespaceDeclarations = new LinkedList<NamespaceDeclaration>();
+ this.attributeDeclarations = new LinkedList<AttributeDeclaration>();
+ reset();
+ }
+
+
+ /**
+ * Set prefix of the element.
+ * @param prefix namespace prefix
+ */
+ public void setPrefix(final String prefix) {
+ this.prefix = prefix;
+ }
+
+ /**
+ * Set local name of the element.
+ *
+ * <p>
+ * This method initializes the element.
+ * </p>
+ *
+ * @param localName local name {@code not null}
+ */
+ public void setLocalName(final String localName) {
+ if (localName == null) {
+ throw new IllegalArgumentException("localName can not be null");
+ }
+ this.localName = localName;
+ }
+
+ /**
+ * Set namespace uri.
+ *
+ * @param namespaceUri namespace uri
+ */
+ public void setNamespaceUri(final String namespaceUri) {
+ this.namespaceUri = namespaceUri;
+ }
+
+ /**
+ * Adds namespace prefix assignment to the element.
+ *
+ * @param prefix prefix (not {@code null})
+ * @param namespaceUri namespace uri
+ */
+ public void addNamespaceDeclaration(final String prefix, final String namespaceUri) {
+ if (null == this.namespaceUri && null != namespaceUri && prefix.equals(emptyIfNull(this.prefix))) {
+ this.namespaceUri = namespaceUri;
+ }
+ this.namespaceDeclarations.add(new NamespaceDeclaration(prefix, namespaceUri));
+ }
+
+ /**
+ * Adds attribute to the element.
+ * @param prefix prefix
+ * @param ns namespace
+ * @param ln local name
+ * @param value value
+ */
+ public void addAttribute(final String prefix, final String ns, final String ln, final String value) {
+ if (ns == null && prefix == null && xmlns.equals(ln)) {
+ this.addNamespaceDeclaration(prefix, value);
+ } else {
+ this.attributeDeclarations.add(new AttributeDeclaration(prefix, ns, ln, value));
+ }
+ }
+
+ /**
+ * Flushes state of this element to the {@code target} element.
+ *
+ * <p>
+ * If this element is initialized then it is added with all the namespace declarations and attributes
+ * to the {@code target} element as a child. The state of this element is reset to uninitialized.
+ * The newly added element object is returned.
+ * </p>
+ * <p>
+ * If this element is not initialized then the {@code target} is returned immediately, nothing else is done.
+ * </p>
+ *
+ * @param target target element
+ * @return {@code target} or new element
+ * @throws XMLStreamException on error
+ */
+ public SOAPElement flushTo(final SOAPElement target) throws XMLStreamException {
+ try {
+ if (this.localName != null) {
+ // add the element appropriately (based on namespace declaration)
+ final SOAPElement newElement;
+ if (this.namespaceUri == null) {
+ // add element with inherited scope
+ newElement = target.addChildElement(this.localName);
+ } else if (prefix == null) {
+ newElement = target.addChildElement(new QName(this.namespaceUri, this.localName));
+ } else {
+ newElement = target.addChildElement(this.localName, this.prefix, this.namespaceUri);
+ }
+ // add namespace declarations
+ for (NamespaceDeclaration namespace : this.namespaceDeclarations) {
+ target.addNamespaceDeclaration(namespace.prefix, namespace.namespaceUri);
+ }
+ // add attribute declarations
+ for (AttributeDeclaration attribute : this.attributeDeclarations) {
+ addAttibuteToElement(newElement,
+ attribute.prefix, attribute.namespaceUri, attribute.localName, attribute.value);
+ }
+ // reset state
+ this.reset();
+
+ return newElement;
+ } else {
+ return target;
+ }
+ // else after reset state -> not initialized
+ } catch (SOAPException e) {
+ throw new XMLStreamException(e);
+ }
+ }
+
+ /**
+ * Is the element initialized?
+ * @return boolean indicating whether it was initialized after last flush
+ */
+ public boolean isInitialized() {
+ return this.localName != null;
+ }
+
+ private void reset() {
+ this.localName = null;
+ this.prefix = null;
+ this.namespaceUri = null;
+ this.namespaceDeclarations.clear();
+ this.attributeDeclarations.clear();
+ }
+
+ private static String emptyIfNull(String s) {
+ return s == null ? "" : s;
+ }
+ }
+
+ static class NamespaceDeclaration {
+ final String prefix;
+ final String namespaceUri;
+
+ NamespaceDeclaration(String prefix, String namespaceUri) {
+ this.prefix = prefix;
+ this.namespaceUri = namespaceUri;
+ }
+ }
+
+ static class AttributeDeclaration {
+ final String prefix;
+ final String namespaceUri;
+ final String localName;
+ final String value;
+
+ AttributeDeclaration(String prefix, String namespaceUri, String localName, String value) {
+ this.prefix = prefix;
+ this.namespaceUri = namespaceUri;
+ this.localName = localName;
+ this.value = value;
+ }
+ }
}