blob: 0bc03b6c088b8925aefaa6cb3bc69cdb7b3ba18a [file] [log] [blame]
/*
* 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.core.MessageContext;
import org.apache.axis2.jaxws.description.EndpointDescription;
import org.apache.axis2.jaxws.message.Message;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* The <tt>MEPContext</tt> is the version of the MessageContext
* that will be given to application handlers as the handler list
* is traversed. It is only to be used by application handlers.
*
* The MEPContext object is constructed using a non-null request
* context. Once the request has been fully processed in the JAX-WS engine,
* the response context should be set on this. Since the response context
* is always last, it takes priority in all MEPContext methods.
*
*/
public class MEPContext implements javax.xml.ws.handler.MessageContext {
// If this a request flow, then the MEP contains the request MC.
// If this a response flow, then the MEP contains both the request MC and the response MC.
// (Note that access to the requestMC properties is sometimes synchronized in the
// response flow.)
protected MessageContext requestMC;
protected MessageContext responseMC;
private Map<String, Scope> scopes; // APPLICATION or HANDLER scope for properties
/*
* Flag to indicate whether we're being called from a handler or an application
* (endpoint or client). Users of MEPContext should use the 'is' and
* 'set' appropriately for this flag. The most likely scenario is to set the
* flag to true after the server-side inbound handlers are complete.
*
* TODO, all methods should use this flag to check for access rights
*/
private boolean ApplicationAccessLocked = false;
/*
* Ideally this would be "protected", but we want the junit tests to see it.
*/
public MEPContext(MessageContext requestMsgCtx) {
this.requestMC = requestMsgCtx;
scopes = new HashMap<String, Scope>();
// make sure the MessageContext points back to this
requestMsgCtx.setMEPContext(this);
}
public EndpointDescription getEndpointDesc() {
if (responseMC != null) {
return responseMC.getEndpointDescription();
}
return requestMC.getEndpointDescription();
}
public MessageContext getRequestMessageContext() {
return requestMC;
}
public MessageContext getResponseMessageContext() {
return responseMC;
}
public MessageContext getMessageContext() {
if (responseMC != null) {
return responseMC;
}
return requestMC;
}
public void setResponseMessageContext(MessageContext responseMC) {
if(this.responseMC != null) {
responseMC.setProperty(javax.xml.ws.handler.MessageContext.OUTBOUND_MESSAGE_ATTACHMENTS,
this.responseMC.getProperty(javax.xml.ws.handler.MessageContext.OUTBOUND_MESSAGE_ATTACHMENTS));
}
// TODO does ApplicationAccessLocked mean anything here? -- method is protected, so probably not
this.responseMC = responseMC;
// if callers are being careful, the responseMC should not be set
// until the engine is done invoking the endpoint, on both server and
// client side. At that point, we can start allowing callers access
// to HANDLER scoped properties again. Set the flag:
ApplicationAccessLocked = false;
}
public void setMessage(Message msg) {
if (responseMC != null) {
responseMC.setMessage(msg);
}
else {
requestMC.setMessage(msg);
}
}
public Scope getScope(String s) {
if (scopes.get(s) == null) {
// JAX-WS default 9.4.1. However, we try to set the scope for
// every incoming property to HANDLER. If a property is coming from
// the axis2 AbstractContext properties bag, we want those to be
// APPLICATION scoped. Those properties may have been set by an
// axis application handler, and may need to be accessible by
// a client app or endpoint.
return Scope.APPLICATION;
}
return scopes.get(s);
}
public void setScope(String s, Scope scope) {
// TODO review next two lines
if (isApplicationAccessLocked()) { // endpoints are not allowed to change property scope. They should all be APPLICATION scoped anyway
return;
}
scopes.put(s, scope);
}
//--------------------------------------------------
// java.util.Map methods
//--------------------------------------------------
public void clear() {
// TODO review
if (isApplicationAccessLocked()) { // endpoints are allowed to clear APPLICATION scoped properties only
Map<String, Object> appScopedProps = getApplicationScopedProperties();
for(Iterator it = appScopedProps.keySet().iterator(); it.hasNext();) {
String key = (String)it.next();
remove(key);
// TODO also remove Scope setting for "key"? How?
}
return;
}
// TODO: REVIEW
// I don't think this will work if the message contexts have a copy
// of the map
if (responseMC != null) {
responseMC.getProperties().clear();
}
synchronized (requestMC) {
requestMC.getProperties().clear();
}
}
public boolean containsKey(Object key) {
if (isApplicationAccessLocked()) {
return getApplicationScopedProperties().containsKey(key);
}
synchronized (requestMC) {
if (responseMC != null) {
boolean containsKey = responseMC.containsKey(key) || requestMC.containsKey(key);
if ((getScope((String)key) == Scope.APPLICATION) || (!isApplicationAccessLocked())) {
return containsKey;
}
}
if ((getScope((String)key) == Scope.APPLICATION) || (!isApplicationAccessLocked())) {
return requestMC.containsKey(key);
}
}
return false;
}
public boolean containsValue(Object value) {
if (isApplicationAccessLocked()) {
return getApplicationScopedProperties().containsValue(value);
}
if (responseMC != null) {
if (responseMC.getProperties().containsValue(value)) {
return true;
}
synchronized (requestMC) {
return requestMC.getProperties().containsValue(value);
}
}
return requestMC.getProperties().containsValue(value);
}
public Set entrySet() {
// TODO should check ApplicationAccessLocked flag
// and return only APPLICATION scoped properties if true
if (isApplicationAccessLocked()) {
return getApplicationScopedProperties().entrySet();
}
HashMap tempProps = new HashMap();
synchronized (requestMC) {
tempProps.putAll(requestMC.getProperties());
}
if (responseMC != null) {
tempProps.putAll(responseMC.getProperties());
}
return tempProps.entrySet();
}
public Object get(Object keyObject) {
String key = (String) keyObject;
if (responseMC != null) {
if (responseMC.getProperty(key) != null) {
if ((getScope((String)key) == Scope.APPLICATION) || (!isApplicationAccessLocked())) {
return responseMC.getProperty(key);
}
}
}
synchronized (requestMC) {
if ((getScope((String)key) == Scope.APPLICATION) || (!isApplicationAccessLocked())) {
return requestMC.getProperty(key);
}
}
return null;
}
public boolean isEmpty() {
if (isApplicationAccessLocked()) {
return getApplicationScopedProperties().isEmpty();
}
synchronized (requestMC) {
if (responseMC != null) {
return requestMC.getProperties().isEmpty() && requestMC.getProperties().isEmpty();
}
return requestMC.getProperties().isEmpty();
}
}
public Set keySet() {
if (isApplicationAccessLocked()) {
return getApplicationScopedProperties().keySet();
}
HashMap tempProps = new HashMap();
synchronized (requestMC) {
tempProps.putAll(requestMC.getProperties());
}
if (responseMC != null) {
tempProps.putAll(responseMC.getProperties());
}
return tempProps.keySet();
}
public Object put(String key, Object value) {
// TODO careful: endpoints may overwrite pre-existing key/value pairs.
// Those key/value pairs may already have a scope attached to them, which
// means an endpoint could "put" a property that is wrongly scoped
if (scopes.get(key) == null) { // check the scopes object directly, not through getScope()!!
setScope(key, Scope.HANDLER);
}
synchronized (requestMC) {
if (requestMC.containsKey(key)) {
return requestMC.setProperty(key, value);
}
if (responseMC != null) {
return responseMC.setProperty(key, value);
}
return requestMC.setProperty(key, value);
}
}
public void putAll(Map t) {
// TODO similar problem as "put"
for(Iterator it = t.entrySet().iterator(); it.hasNext();) {
Entry<String, Object> entry = (Entry)it.next();
if (getScope(entry.getKey()) == null) {
setScope(entry.getKey(), Scope.HANDLER);
}
}
if (responseMC != null) {
responseMC.setProperties(t);
}
else {
synchronized (requestMC) {
requestMC.setProperties(t);
}
}
}
public Object remove(Object key) {
// check ApplicationAccessLocked flag and prevent removal of HANDLER scoped props
if (isApplicationAccessLocked()) {
if (getScope((String)key).equals(Scope.HANDLER)) {
return null;
}
}
// yes, remove from both and return the right object
// TODO This won't work because getProperties returns a temporary map
Object retVal = null;
if (responseMC != null) {
retVal = responseMC.getProperties().remove(key);
}
synchronized (requestMC) {
if (retVal == null) {
return requestMC.getProperties().remove(key);
}
else {
requestMC.getProperties().remove(key);
}
}
return retVal;
}
public int size() {
if (isApplicationAccessLocked()) {
return getApplicationScopedProperties().size();
}
// The properties must be combined together because some
// keys may be the same on the request and the response.
HashMap tempProps = new HashMap();
synchronized (requestMC) {
tempProps.putAll(requestMC.getProperties());
}
if (responseMC != null) {
tempProps.putAll(responseMC.getProperties());
}
return tempProps.size();
}
public Collection values() {
if (isApplicationAccessLocked()) {
return getApplicationScopedProperties().values();
}
HashMap tempProps = new HashMap();
synchronized (requestMC) {
tempProps.putAll(requestMC.getProperties());
}
if (responseMC != null) {
tempProps.putAll(responseMC.getProperties());
}
return tempProps.values();
}
public Message getMessageObject() {
// TODO does ApplicationAccessLocked apply here?
if (responseMC != null) {
return responseMC.getMessage();
}
return requestMC.getMessage();
}
public boolean isApplicationAccessLocked() {
// since MEPContext is both a wrapper and a subclass, we need to be careful to set it only on the wrapper object:
if (this == requestMC.getMEPContext()) { // object compare, I am the wrapper object
return ApplicationAccessLocked;
}
if (responseMC == null) {
return requestMC.getMEPContext().isApplicationAccessLocked();
}
else {
return responseMC.getMEPContext().isApplicationAccessLocked() || requestMC.getMEPContext().isApplicationAccessLocked();
}
}
public void setApplicationAccessLocked(boolean applicationAccessLocked) {
// since MEPContext is both a wrapper and a subclass, we need to be careful to set it only on the wrapper object:
if (this == requestMC.getMEPContext()) { // object compare, I am the wrapper object
ApplicationAccessLocked = applicationAccessLocked;
}
else {
requestMC.getMEPContext().setApplicationAccessLocked(applicationAccessLocked);
}
}
/**
* The returned tempMap should be used as a read-only map as changes to it will
* not propogate into the requestMC or responseMC
*
* Watch out for infinite loop if you call another method in this class that uses this method.
*
* @return
*/
public Map<String, Object> getApplicationScopedProperties() {
Map<String, Object> tempMap = new HashMap<String, Object>();
if (!scopes.containsValue(Scope.APPLICATION)) {
return tempMap;
}
synchronized (requestMC) {
for(Iterator it = requestMC.getProperties().entrySet().iterator(); it.hasNext();) {
Entry entry = (Entry)it.next();
if (getScope((String)entry.getKey()).equals(Scope.APPLICATION)) {
tempMap.put((String)entry.getKey(), entry.getValue());
}
}
}
if (responseMC != null) {
for(Iterator it = responseMC.getProperties().entrySet().iterator(); it.hasNext();) {
Entry entry = (Entry)it.next();
if (getScope((String)entry.getKey()).equals(Scope.APPLICATION)) {
tempMap.put((String)entry.getKey(), entry.getValue());
}
}
}
return tempMap;
}
}