org.apache.axis2.jaxws.handler.SOAPHeadersAdapter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of axis2-jaxws Show documentation
Show all versions of axis2-jaxws Show documentation
Axis2 JAXWS Implementation
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.axis2.jaxws.handler;
import org.apache.axis2.jaxws.Constants;
import org.apache.axis2.jaxws.ExceptionFactory;
import org.apache.axis2.jaxws.core.MessageContext;
import org.apache.axis2.jaxws.message.Block;
import org.apache.axis2.jaxws.message.Message;
import org.apache.axis2.jaxws.message.factory.XMLStringBlockFactory;
import org.apache.axis2.jaxws.registry.FactoryRegistry;
import org.apache.axis2.jaxws.utility.JavaUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* The JAX-WS exposes soap header properties whose value is Map>. The
* QName is the name of the header and List are the xml values of the headers for qname.
*
* The JAX-WS MessageContext stores soap headers in an Axiom tree object located on the JAX-WS
* Message.
*
* This class, SOAPHeadersAdapter, is an adapter between the Map> interface needed
* by the properties and the actual implementation. All useful function is delegated through the MessageContext, so
* that we only have one copy of the soap header information.
*
* To use this class, invoke the install method. This will create an SOAPHeaderAdapter (if necessary) and install it
* on to provide the JAX-WS soap headers property. (See BaseMessageContext.)
*/
public class SOAPHeadersAdapter implements Map> {
private static final Log log = LogFactory.getLog(SOAPHeadersAdapter.class);
private MessageContext mc; // MessageContext which provides the backing implementation of Attachments
private boolean isOutbound; // IsOutbound
private String property;
/**
* Add the AttachmentAdapter as the property for the inbound and/or
* outbound attachment property
* @param mc MessageContext
*/
public static void install(MessageContext mc) {
Message m = mc.getMessage();
if (m == null) {
// Probably a unit test, can't continue.
return;
}
boolean isOutbound = mc.isOutbound();
if (log.isTraceEnabled()) {
log.trace("Installing SOAPHeadersAdapter: " +
JavaUtils.callStackToString());
}
String property = (isOutbound) ?
Constants.JAXWS_OUTBOUND_SOAP_HEADERS :
Constants.JAXWS_INBOUND_SOAP_HEADERS;
// See if there is an existing map
Object map = mc.getProperty(property);
// Reuse existing Adapter
if (map instanceof SOAPHeadersAdapter) {
if (log.isDebugEnabled()) {
log.debug("A SOAPHeadersAdapter is already installed. Reusing the existing one.");
}
return;
}
// Create a new AttachmentsAdapter and set it on the property
SOAPHeadersAdapter sha =
new SOAPHeadersAdapter(mc,
isOutbound);
if (map != null) {
// Copy the existing Map contents to this new adapter
sha.putAll((Map>) map);
}
mc.setPropertyNoReturn(property, sha);
}
/**
* The backing storage of the Attachments is the JAX-WS MessageContext.
* Intentionally private, use install(MessageContext)
*/
private SOAPHeadersAdapter(MessageContext mc,
boolean isOutbound) {
this.mc = mc;
this.isOutbound = isOutbound;
this.property = (isOutbound) ?
Constants.JAXWS_OUTBOUND_SOAP_HEADERS :
Constants.JAXWS_INBOUND_SOAP_HEADERS;
if (log.isDebugEnabled()) {
log.debug("Init SOAPHeadersAdapter for " + property);
}
}
// These @Override annotations break JDK 1.5 compilation... AFAIK we have not discussed
// forcing Axis2 devs to JDK 1.6, so commenting them out for now... --gdaniels
public void clear() {
// Throw unsupported operation exception per Map javadoc
// for any method that is not supported.
// this should remain unsupported as handlers or client
// apps would be able to easily wipe important soap headers
throw new UnsupportedOperationException();
}
public boolean containsKey(Object key) {
Set keys = this.keySet();
return keys.contains(key);
}
public boolean containsValue(Object value) {
Set keys = this.keySet();
for(QName key: keys) {
List tryValue = get(key);
if (tryValue == value ||
value.equals(tryValue)) {
return true;
}
}
return false;
}
public Set>> entrySet() {
// Previous implementation of this method called tempMap.putAll(this), which resulted
// in an infinite loop due to Map calling back into this entrySet() method. So, don't do that!
Map> tempMap = new HashMap>();
Set keys = this.keySet();
QName key;
for (Iterator it = keys.iterator();it.hasNext();) {
key = (QName)it.next();
tempMap.put(key, this.get(key));
}
return tempMap.entrySet();
}
/**
* Returns a list of XML strings that have the same namespace as the QName key. The
* returned list is not "live"; it manipulating the list will not result in changed
* headers on the message.
* @param _key Object -- QName key of header XML strings you intend to retrieve
*/
public List get(Object _key) {
// notify the HandlerChainProcessor that a transformation has occurred possibly due to a handler method call into here
HandlerChainProcessor.trackInternalCall(mc, HandlerChainProcessor.TRACKER.SOAP_HEADERS_ADAPTER_CALLED);
try {
if (!(keySet().contains(_key))) {
return null;
}
QName key = (QName) _key;
Message m = mc.getMessage();
List blocks = m.getHeaderBlocks(key.getNamespaceURI(),
key.getLocalPart(),
null,
getXMLStringBlockFactory(),
null);
if (blocks == null || blocks.size() == 0) {
return null;
}
// Get the strings from the blocks
ArrayList xmlStrings = new ArrayList();
for (int i=0; i keySet() {
// notify the HandlerChainProcessor that a transformation has occurred possibly due to a handler method call into here
HandlerChainProcessor.trackInternalCall(mc, HandlerChainProcessor.TRACKER.SOAP_HEADERS_ADAPTER_CALLED);
Message m = mc.getMessage();
return m.getHeaderQNames();
}
/**
* put will inject the headers into the SOAP message immediately
* @param key Object -- QName key of header XML strings you wish to be put on the SOAP header
* @param values List -- list of XML strings that have the same namespace as the QName key
*/
public List put(QName key, List values) {
// notify the HandlerChainProcessor that a transformation has occurred possibly due to a handler method call into here
HandlerChainProcessor.trackInternalCall(mc, HandlerChainProcessor.TRACKER.SOAP_HEADERS_ADAPTER_CALLED);
Message m = mc.getMessage();
if (log.isDebugEnabled()) {
log.debug("put(" + key + " , " + values + ")");
}
// Get the old value
List old = get(key);
if (values != null) {
if (old != null) {
// Replace the existing header blocks
m.removeHeaderBlock(key.getNamespaceURI(), key.getLocalPart());
}
for (int i=0; i < values.size(); i++) {
String value = values.get(i);
Block block = getXMLStringBlockFactory().createFrom(value, null, key);
m.appendHeaderBlock(key.getNamespaceURI(), key.getLocalPart(), block);
}
}
return old;
}
/**
* putAll will inject the headers into the SOAP message immediately
*/
public void putAll(Map extends QName, ? extends List> t) {
for(Entry extends QName, ? extends List> entry: t.entrySet()) {
QName key = entry.getKey();
List value = entry.getValue();
put(key, value);
}
}
/**
* remove will immediately remove the headers from the SOAP message that match the QName key
* @param _key Object -- QName key of header XML strings you wish to remove from the SOAP header
*/
public List remove(Object _key) {
// notify the HandlerChainProcessor that a transformation has occurred possibly due to a handler method call into here
HandlerChainProcessor.trackInternalCall(mc, HandlerChainProcessor.TRACKER.SOAP_HEADERS_ADAPTER_CALLED);
try {
if (!(keySet().contains(_key))) {
return null;
}
if (!(_key instanceof QName)) {
throw ExceptionFactory.makeWebServiceException("key must be of type " + QName.class.getName());
}
QName key = (QName) _key;
if (log.isDebugEnabled()) {
log.debug("remove(" + key + ")");
}
// Get the old value
List old = get(key);
Message m = mc.getMessage();
List blocks = m.getHeaderBlocks(key.getNamespaceURI(),
key.getLocalPart(),
null,
getXMLStringBlockFactory(),
null);
if (blocks == null || blocks.size() == 0) {
return null;
}
// Get the strings from the blocks
ArrayList xmlStrings = new ArrayList();
for (Block block : blocks) {
String value = (block == null) ? null : (String)block.getBusinessObject(false);
xmlStrings.add(value);
m.removeHeaderBlock(key.getNamespaceURI(), key.getLocalPart());
}
keySet().remove(key);
return old;
} catch (Throwable t) {
throw ExceptionFactory.makeWebServiceException(t);
}
}
public int size() {
return this.keySet().size();
}
public Collection> values() {
/*
* Previous implementation of this method called tempMap.putAll(this), which resulted
* in an infinite loop due to Map calling back into this values() method. So, don't do that!
*/
Map> tempMap = new HashMap>();
Set keys = this.keySet();
QName key;
for (QName key1 : keys) {
key = key1;
tempMap.put(key, this.get(key));
}
return tempMap.values();
}
private XMLStringBlockFactory getXMLStringBlockFactory() {
return (XMLStringBlockFactory)
FactoryRegistry.getFactory(XMLStringBlockFactory.class);
}
}