| /* |
| * Copyright 2001-2004 The Apache Software Foundation. |
| * |
| * Licensed 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.axis ; |
| |
| import org.apache.axis.attachments.Attachments; |
| import org.apache.axis.client.AxisClient; |
| import org.apache.axis.components.logger.LogFactory; |
| import org.apache.axis.description.OperationDesc; |
| import org.apache.axis.description.ServiceDesc; |
| import org.apache.axis.encoding.TypeMapping; |
| import org.apache.axis.encoding.TypeMappingRegistry; |
| import org.apache.axis.constants.Style; |
| import org.apache.axis.constants.Use; |
| import org.apache.axis.handlers.soap.SOAPService; |
| import org.apache.axis.schema.SchemaVersion; |
| import org.apache.axis.session.Session; |
| import org.apache.axis.soap.SOAPConstants; |
| import org.apache.axis.utils.JavaUtils; |
| import org.apache.axis.utils.LockableHashtable; |
| import org.apache.axis.utils.Messages; |
| import org.apache.commons.logging.Log; |
| |
| import javax.xml.namespace.QName; |
| import javax.xml.rpc.Call; |
| import javax.xml.rpc.handler.soap.SOAPMessageContext; |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.Hashtable; |
| |
| // fixme: fields are declared throughout this class, some at the top, and some |
| // near to where they are used. We should move all field declarations into a |
| // single block - it makes it easier to see what is decalred in this class and |
| // what is inherited. It also makes it easier to find them. |
| /** |
| * A MessageContext is the Axis implementation of the javax |
| * SOAPMessageContext class, and is core to message processing |
| * in handlers and other parts of the system. |
| * |
| * This class also contains constants for accessing some |
| * well-known properties. Using a hierarchical namespace is |
| * strongly suggested in order to lower the chance for |
| * conflicts. |
| * |
| * (These constants should be viewed as an explicit list of well |
| * known and widely used context keys, there's nothing wrong |
| * with directly using the key strings. This is the reason for |
| * the hierarchical constant namespace. |
| * |
| * Actually I think we might just list the keys in the docs and |
| * provide no such constants since they create yet another |
| * namespace, but we'd have no compile-time checks then. |
| * |
| * Whaddya think? - todo by Jacek) |
| * |
| * |
| * @author Doug Davis (dug@us.ibm.com) |
| * @author Jacek Kopecky (jacek@idoox.com) |
| */ |
| public class MessageContext implements SOAPMessageContext { |
| /** The <code>Log</code> used for logging all messages. */ |
| protected static Log log = |
| LogFactory.getLog(MessageContext.class.getName()); |
| |
| /** |
| * The request message. If we're on the client, this is the outgoing |
| * message heading to the server. If we're on the server, this is the |
| * incoming message we've received from the client. |
| */ |
| private Message requestMessage; |
| |
| /** |
| * The response message. If we're on the server, this is the outgoing |
| * message heading back to the client. If we're on the client, this is the |
| * incoming message we've received from the server. |
| */ |
| private Message responseMessage; |
| |
| /** |
| * That unique key/name that the next router/dispatch handler should use |
| * to determine what to do next. |
| */ |
| private String targetService; |
| |
| /** |
| * The name of the Transport which this message was received on (or is |
| * headed to, for the client). |
| */ |
| private String transportName; |
| |
| /** |
| * The default <code>ClassLoader</code> that this service should use. |
| */ |
| private ClassLoader classLoader; |
| |
| /** |
| * The AxisEngine which this context is involved with. |
| */ |
| private AxisEngine axisEngine; |
| |
| /** |
| * A Session associated with this request. |
| */ |
| private Session session; |
| |
| /** |
| * Should we track session state, or not? |
| * default is not. |
| * Could potentially refactor this so that |
| * maintainSession iff session != null... |
| */ |
| private boolean maintainSession = false; |
| |
| // fixme: ambiguity here due to lac of docs - havePassedPivot vs |
| // request/response, vs sending/processing & recieving/responding |
| // I may have just missed the key bit of text |
| /** |
| * Are we doing request stuff, or response stuff? True if processing |
| * response (I think). |
| */ |
| private boolean havePassedPivot = false; |
| |
| /** |
| * Maximum amount of time to wait on a request, in milliseconds. |
| */ |
| private int timeout = Constants.DEFAULT_MESSAGE_TIMEOUT; |
| |
| /** |
| * An indication of whether we require "high fidelity" recording of |
| * deserialized messages for this interaction. Defaults to true for |
| * now, and can be set to false, usually at service-dispatch time. |
| */ |
| private boolean highFidelity = true; |
| |
| /** |
| * Storage for an arbitrary bag of properties associated with this |
| * MessageContext. |
| */ |
| private LockableHashtable bag = new LockableHashtable(); |
| |
| /* |
| * These variables are logically part of the bag, but are separated |
| * because they are used often and the Hashtable is more expensive. |
| * |
| * fixme: this may be fixed by moving to a plain Map impl like HashMap. |
| * Alternatively, we could hide all this magic behind a custom Map impl - |
| * is synchronization on the map needed? these properties aren't |
| * synchronized so I'm guessing not. |
| */ |
| private String username = null; |
| private String password = null; |
| private String encodingStyle = Use.ENCODED.getEncoding(); |
| private boolean useSOAPAction = false; |
| private String SOAPActionURI = null; |
| |
| /** |
| * SOAP Actor roles. |
| */ |
| private String[] roles; |
| |
| /** Our SOAP namespaces and such. */ |
| private SOAPConstants soapConstants = Constants.DEFAULT_SOAP_VERSION; |
| |
| /** Schema version information - defaults to 2001. */ |
| private SchemaVersion schemaVersion = SchemaVersion.SCHEMA_2001; |
| |
| /** Our current operation. */ |
| private OperationDesc currentOperation = null; |
| |
| /** |
| * The current operation. |
| * |
| * @return the current operation; may be <code>null</code> |
| */ |
| public OperationDesc getOperation() |
| { |
| return currentOperation; |
| } |
| |
| /** |
| * Set the current operation. |
| * |
| * @param operation the <code>Operation</code> this context is executing |
| */ |
| public void setOperation(OperationDesc operation) |
| { |
| currentOperation = operation; |
| } |
| |
| /** |
| * Returns a list of operation descriptors that could may |
| * possibly match a body containing an element of the given QName. |
| * For non-DOCUMENT, the list of operation descriptors that match |
| * the name is returned. For DOCUMENT, all the operations that have |
| * qname as a parameter are returned |
| * |
| * @param qname of the first element in the body |
| * @return list of operation descriptions |
| * @throws AxisFault if the operation names could not be looked up |
| */ |
| public OperationDesc [] getPossibleOperationsByQName(QName qname) throws AxisFault |
| { |
| if (currentOperation != null) { |
| return new OperationDesc [] { currentOperation }; |
| } |
| |
| OperationDesc [] possibleOperations = null; |
| |
| if (serviceHandler == null) { |
| try { |
| if (log.isDebugEnabled()) { |
| log.debug(Messages.getMessage("dispatching00", |
| qname.getNamespaceURI())); |
| } |
| |
| // Try looking this QName up in our mapping table... |
| setService(axisEngine.getConfig(). |
| getServiceByNamespaceURI(qname.getNamespaceURI())); |
| } catch (ConfigurationException e) { |
| // Didn't find one... |
| } |
| |
| } |
| |
| if (serviceHandler != null) { |
| ServiceDesc desc = serviceHandler.getInitializedServiceDesc(this); |
| |
| if (desc != null) { |
| if (desc.getStyle() != Style.DOCUMENT) { |
| possibleOperations = desc.getOperationsByQName(qname); |
| } else { |
| // DOCUMENT Style |
| // Get all of the operations that have qname as |
| // a possible parameter QName |
| ArrayList allOperations = desc.getOperations(); |
| ArrayList foundOperations = new ArrayList(); |
| for (int i=0; i < allOperations.size(); i++ ) { |
| OperationDesc tryOp = |
| (OperationDesc) allOperations.get(i); |
| if (tryOp.getParamByQName(qname) != null) { |
| foundOperations.add(tryOp); |
| } |
| } |
| if (foundOperations.size() > 0) { |
| possibleOperations = (OperationDesc[]) |
| JavaUtils.convert(foundOperations, |
| OperationDesc[].class); |
| } |
| } |
| } |
| } |
| return possibleOperations; |
| } |
| |
| /** |
| * get the first possible operation that could match a |
| * body containing an element of the given QName. Sets the currentOperation |
| * field in the process; if that field is already set then its value |
| * is returned instead |
| * @param qname name of the message body |
| * @return an operation or null |
| * @throws AxisFault |
| */ |
| public OperationDesc getOperationByQName(QName qname) throws AxisFault |
| { |
| if (currentOperation == null) { |
| OperationDesc [] possibleOperations = getPossibleOperationsByQName(qname); |
| if (possibleOperations != null && possibleOperations.length > 0) { |
| currentOperation = possibleOperations[0]; |
| } |
| } |
| |
| return currentOperation; |
| } |
| |
| /** |
| * Get the active message context. |
| * |
| * @return the current active message context |
| */ |
| public static MessageContext getCurrentContext() { |
| return AxisEngine.getCurrentMessageContext(); |
| } |
| |
| /** |
| * Temporary directory to store attachments. |
| */ |
| protected static String systemTempDir= null; |
| /** |
| * set the temp dir |
| * TODO: move this piece of code out of this class and into a utilities |
| * class. |
| */ |
| static { |
| try { |
| //get the temp dir from the engine |
| systemTempDir=AxisProperties.getProperty(AxisEngine.ENV_ATTACHMENT_DIR); |
| } catch(Throwable t) { |
| systemTempDir= null; |
| } |
| |
| if(systemTempDir== null) { |
| try { |
| //or create and delete a file in the temp dir to make |
| //sure we have write access to it. |
| File tf= File.createTempFile("Axis", ".tmp"); |
| File dir= tf.getParentFile(); |
| if (tf.exists()) { |
| tf.delete(); |
| } |
| if (dir != null) { |
| systemTempDir= dir.getCanonicalPath(); |
| } |
| } catch(Throwable t) { |
| log.debug("Unable to find a temp dir with write access"); |
| systemTempDir= null; |
| } |
| } |
| } |
| |
| /** |
| * Create a message context. |
| * @param engine the controlling axis engine. Null is actually accepted here, |
| * though passing a null engine in is strongly discouraged as many of the methods |
| * assume that it is in fact defined. |
| */ |
| public MessageContext(AxisEngine engine) { |
| this.axisEngine = engine; |
| |
| if(null != engine){ |
| java.util.Hashtable opts= engine.getOptions(); |
| String attachmentsdir= null; |
| if(null!=opts) { |
| attachmentsdir= (String) opts.get(AxisEngine.PROP_ATTACHMENT_DIR); |
| } |
| if(null == attachmentsdir) { |
| attachmentsdir= systemTempDir; |
| } |
| if(attachmentsdir != null){ |
| setProperty(ATTACHMENTS_DIR, attachmentsdir); |
| } |
| |
| // If SOAP 1.2 has been specified as the default for the engine, |
| // switch the constants over. |
| String defaultSOAPVersion = (String)engine.getOption( |
| AxisEngine.PROP_SOAP_VERSION); |
| if (defaultSOAPVersion != null && "1.2".equals(defaultSOAPVersion)) { |
| setSOAPConstants(SOAPConstants.SOAP12_CONSTANTS); |
| } |
| |
| String singleSOAPVersion = (String)engine.getOption( |
| AxisEngine.PROP_SOAP_ALLOWED_VERSION); |
| if (singleSOAPVersion != null) { |
| if ("1.2".equals(singleSOAPVersion)) { |
| setProperty(Constants.MC_SINGLE_SOAP_VERSION, |
| SOAPConstants.SOAP12_CONSTANTS); |
| } else if ("1.1".equals(singleSOAPVersion)) { |
| setProperty(Constants.MC_SINGLE_SOAP_VERSION, |
| SOAPConstants.SOAP11_CONSTANTS); |
| } |
| } |
| } |
| } |
| |
| /** |
| * during finalization, the dispose() method is called. |
| * @see #dispose() |
| */ |
| protected void finalize() { |
| dispose(); |
| } |
| |
| /** |
| * Mappings of QNames to serializers/deserializers (and therfore |
| * to Java types). |
| */ |
| private TypeMappingRegistry mappingRegistry = null; |
| |
| /** |
| * Replace the engine's type mapping registry with a local one. This will |
| * have no effect on any type mappings obtained before this call. |
| * |
| * @param reg the new <code>TypeMappingRegistry</code> |
| */ |
| public void setTypeMappingRegistry(TypeMappingRegistry reg) { |
| mappingRegistry = reg; |
| } |
| |
| /** |
| * Get the currently in-scope type mapping registry. |
| * |
| * By default, will return a reference to the AxisEngine's TMR until |
| * someone sets our local one (usually as a result of setting the |
| * serviceHandler). |
| * |
| * @return the type mapping registry to use for this request. |
| */ |
| public TypeMappingRegistry getTypeMappingRegistry() { |
| if (mappingRegistry == null) { |
| return axisEngine.getTypeMappingRegistry(); |
| } |
| |
| return mappingRegistry; |
| } |
| |
| /** |
| * Return the type mapping currently in scope for our encoding style. |
| * |
| * @return the type mapping |
| */ |
| public TypeMapping getTypeMapping() |
| { |
| return (TypeMapping)getTypeMappingRegistry(). |
| getTypeMapping(encodingStyle); |
| } |
| |
| /** |
| * The name of the transport for this context. |
| * |
| * @return the transport name |
| */ |
| public String getTransportName() |
| { |
| return transportName; |
| } |
| |
| // fixme: the transport names should be a type-safe e-num, or the range |
| // of legal values should be specified in the documentation and validated |
| // in the method (raising IllegalArgumentException) |
| /** |
| * Set the transport name for this context. |
| * |
| * @param transportName the name of the transport |
| */ |
| public void setTransportName(String transportName) |
| { |
| this.transportName = transportName; |
| } |
| |
| /** |
| * Get the <code>SOAPConstants</code> used by this message context. |
| * |
| * @return the soap constants |
| */ |
| public SOAPConstants getSOAPConstants() { |
| return soapConstants; |
| } |
| |
| /** |
| * Set the <code>SOAPConstants</code> used by this message context. |
| * This may also affect the encoding style. |
| * |
| * @param soapConstants the new soap constants to use |
| */ |
| public void setSOAPConstants(SOAPConstants soapConstants) { |
| // when changing SOAP versions, remember to keep the encodingURI |
| // in synch. |
| if (this.soapConstants.getEncodingURI().equals(encodingStyle)) { |
| encodingStyle = soapConstants.getEncodingURI(); |
| } |
| |
| this.soapConstants = soapConstants; |
| } |
| |
| /** |
| * Get the XML schema version information. |
| * |
| * @return the <code>SchemaVersion</code> in use |
| */ |
| public SchemaVersion getSchemaVersion() { |
| return schemaVersion; |
| } |
| |
| /** |
| * Set the XML schema version this message context will use. |
| * |
| * @param schemaVersion the new <code>SchemaVersion</code> |
| */ |
| public void setSchemaVersion(SchemaVersion schemaVersion) { |
| this.schemaVersion = schemaVersion; |
| } |
| |
| /** |
| * Get the current session. |
| * |
| * @return the <code>Session</code> this message context is within |
| */ |
| public Session getSession() |
| { |
| return session; |
| } |
| |
| /** |
| * Set the current session. |
| * |
| * @param session the new <code>Session</code> |
| */ |
| public void setSession(Session session) |
| { |
| this.session = session; |
| } |
| |
| /** |
| * Indicates if the opration is encoded. |
| * |
| * @return <code>true</code> if it is encoded, <code>false</code> otherwise |
| */ |
| public boolean isEncoded() { |
| return (getOperationUse() == Use.ENCODED); |
| //return soapConstants.getEncodingURI().equals(encodingStyle); |
| } |
| |
| /** |
| * Set whether we are maintaining session state. |
| * |
| * @param yesno flag to set to <code>true</code> to maintain sessions |
| */ |
| public void setMaintainSession (boolean yesno) { |
| maintainSession = yesno; |
| } |
| |
| /** |
| * Discover if we are maintaining session state. |
| * |
| * @return <code>true</code> if we are maintaining state, <code>false</code> |
| * otherwise |
| */ |
| public boolean getMaintainSession () { |
| return maintainSession; |
| } |
| |
| /** |
| * Get the request message. |
| * |
| * @return the request message (may be null). |
| */ |
| public Message getRequestMessage() { |
| return requestMessage ; |
| } |
| |
| /** |
| * Set the request message, and make sure that message is associated |
| * with this MessageContext. |
| * |
| * @param reqMsg the new request Message. |
| */ |
| public void setRequestMessage(Message reqMsg) { |
| requestMessage = reqMsg ; |
| if (requestMessage != null) { |
| requestMessage.setMessageContext(this); |
| } |
| } |
| |
| /** |
| * Get the response message. |
| * |
| * @return the response message (may be null). |
| */ |
| public Message getResponseMessage() { return responseMessage ; } |
| |
| /** |
| * Set the response message, and make sure that message is associated |
| * with this MessageContext. |
| * |
| * @param respMsg the new response Message. |
| */ |
| public void setResponseMessage(Message respMsg) { |
| responseMessage = respMsg; |
| if (responseMessage != null) { |
| responseMessage.setMessageContext(this); |
| |
| //if we have received attachments of a particular type |
| // than that should be the default type to send. |
| Message reqMsg = getRequestMessage(); |
| if (null != reqMsg) { |
| Attachments reqAttch = reqMsg.getAttachmentsImpl(); |
| Attachments respAttch = respMsg.getAttachmentsImpl(); |
| if (null != reqAttch && null != respAttch) { |
| if (respAttch.getSendType() == Attachments.SEND_TYPE_NOTSET) |
| //only if not explicity set. |
| respAttch.setSendType(reqAttch.getSendType()); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Return the current (i.e. request before the pivot, response after) |
| * message. |
| * |
| * @return the current <code>Message</code> |
| */ |
| public Message getCurrentMessage() |
| { |
| return (havePassedPivot ? responseMessage : requestMessage); |
| } |
| |
| /** |
| * Gets the SOAPMessage from this message context. |
| * |
| * @return the <code>SOAPMessage</code>, <code>null</code> if no request |
| * <code>SOAPMessage</code> is present in this |
| * <code>SOAPMessageContext</code> |
| */ |
| public javax.xml.soap.SOAPMessage getMessage() { |
| return getCurrentMessage(); |
| } |
| |
| /** |
| * Set the current message. This will set the request before the pivot, |
| * and the response afterwards, as guaged by the passedPivod property. |
| * |
| * @param curMsg the <code>Message</code> to assign |
| */ |
| public void setCurrentMessage(Message curMsg) |
| { |
| if ( curMsg != null ) |
| curMsg.setMessageContext(this); |
| |
| if (havePassedPivot) { |
| responseMessage = curMsg; |
| } else { |
| requestMessage = curMsg; |
| } |
| } |
| |
| /** |
| * Sets the SOAPMessage for this message context. |
| * This is equivalent to casting <code>message</code> to |
| * <code>Message</code> and then passing it on to |
| * <code>setCurrentMessage()</code>. |
| * |
| * @param message the <code>SOAPMessage</code> this context is for |
| */ |
| public void setMessage(javax.xml.soap.SOAPMessage message) { |
| setCurrentMessage((Message)message); |
| } |
| |
| /** |
| * Determine when we've passed the pivot. |
| * |
| * @return <code>true</code> if we have, <code>false</code> otherwise |
| */ |
| public boolean getPastPivot() |
| { |
| return havePassedPivot; |
| } |
| |
| // fixme: is there any legitimate case where we could pass the pivot and |
| // then go back again? Is there documentation about the life-cycle of a |
| // MessageContext, and in particular the re-use of instances that would be |
| // relevant? |
| /** |
| * Indicate when we've passed the pivot. |
| * |
| * @param pastPivot true if we are past the pivot point, false otherwise |
| */ |
| public void setPastPivot(boolean pastPivot) |
| { |
| havePassedPivot = pastPivot; |
| } |
| |
| /** |
| * Set timeout in our MessageContext. |
| * |
| * @param value the maximum amount of time, in milliseconds |
| */ |
| public void setTimeout (int value) { |
| timeout = value; |
| } |
| |
| /** |
| * Get timeout from our MessageContext. |
| * |
| * @return value the maximum amount of time, in milliseconds |
| */ |
| public int getTimeout () { |
| return timeout; |
| } |
| |
| /** |
| * Get the classloader, implicitly binding to the thread context |
| * classloader if an override has not been supplied. |
| * |
| * @return the class loader |
| */ |
| public ClassLoader getClassLoader() { |
| if ( classLoader == null ) { |
| classLoader = Thread.currentThread().getContextClassLoader(); |
| } |
| return( classLoader ); |
| } |
| |
| /** |
| * Set a new classloader. Setting to null will result in getClassLoader() |
| * binding back to the thread context class loader. |
| * |
| * @param cl the new <code>ClassLoader</code> or <code>null</code> |
| */ |
| public void setClassLoader(ClassLoader cl ) { |
| classLoader = cl ; |
| } |
| |
| /** |
| * Get the name of the targed service for this message. |
| * |
| * @return the target service |
| */ |
| public String getTargetService() { |
| return targetService; |
| } |
| |
| /** |
| * Get the axis engine. This will be <code>null</code> if the message was |
| * created outside an engine |
| * |
| * @return the current axis engine |
| */ |
| public AxisEngine getAxisEngine() |
| { |
| return axisEngine; |
| } |
| |
| /** |
| * Set the target service for this message. |
| * <p> |
| * This looks up the named service in the registry, and has |
| * the side effect of setting our TypeMappingRegistry to the |
| * service's. |
| * |
| * @param tServ the name of the target service |
| * @throws AxisFault if anything goes wrong in resolving or setting the |
| * service |
| */ |
| public void setTargetService(String tServ) throws AxisFault { |
| log.debug("MessageContext: setTargetService(" + tServ+")"); |
| |
| if (tServ == null) { |
| setService(null); |
| } |
| else { |
| try { |
| setService(getAxisEngine().getService(tServ)); |
| } catch (AxisFault fault) { |
| // If we're on the client, don't throw this fault... |
| if (!isClient()) { |
| throw fault; |
| } |
| } |
| } |
| targetService = tServ; |
| } |
| |
| /** ServiceHandler is the handler that is the "service". This handler |
| * can (and probably will actually be a chain that contains the |
| * service specific request/response/pivot point handlers |
| */ |
| private SOAPService serviceHandler ; |
| |
| /** |
| * Get the <code>SOAPService</code> used to handle services in this |
| * context. |
| * |
| * @return the service handler |
| */ |
| public SOAPService getService() { |
| return serviceHandler; |
| } |
| |
| /** |
| * Set the <code>SOAPService</code> used to handle services in this |
| * context. This method configures a wide range of |
| * <code>MessageContext</code> properties to suit the handler. |
| * |
| * @param sh the new service handler |
| * @throws AxisFault if the service could not be set |
| */ |
| public void setService(SOAPService sh) throws AxisFault |
| { |
| log.debug("MessageContext: setServiceHandler("+sh+")"); |
| serviceHandler = sh; |
| if (sh != null) { |
| if(!sh.isRunning()) { |
| throw new AxisFault(Messages.getMessage("disabled00")); |
| } |
| targetService = sh.getName(); |
| SOAPService service = sh; |
| TypeMappingRegistry tmr = service.getTypeMappingRegistry(); |
| setTypeMappingRegistry(tmr); |
| |
| // styles are not "soap version aware" so compensate... |
| setEncodingStyle(service.getUse().getEncoding()); |
| |
| // This MessageContext should now defer properties it can't find |
| // to the Service's options. |
| bag.setParent(sh.getOptions()); |
| |
| // Note that we need (or don't need) high-fidelity SAX recording |
| // of deserialized messages according to the setting on the |
| // new service. |
| highFidelity = service.needsHighFidelityRecording(); |
| |
| service.getInitializedServiceDesc(this); |
| } |
| } |
| |
| /** |
| * Let us know whether this is the client or the server. |
| * |
| * @return true if we are a client |
| */ |
| public boolean isClient() |
| { |
| return (axisEngine instanceof AxisClient); |
| } |
| |
| // fixme: public final statics tend to go in a block at the top of the |
| // class deffinition, not marooned in the middle |
| // fixme: chose public static final /or/ public final static |
| /** Contains an instance of Handler, which is the |
| * ServiceContext and the entrypoint of this service. |
| * |
| * (if it has been so configured - will our deployment |
| * tool do this by default? - todo by Jacek) |
| */ |
| public static final String ENGINE_HANDLER = "engine.handler"; |
| |
| /** This String is the URL that the message came to. |
| */ |
| public static final String TRANS_URL = "transport.url"; |
| |
| /** Has a quit been requested? Hackish... but useful... -- RobJ */ |
| public static final String QUIT_REQUESTED = "quit.requested"; |
| |
| /** Place to store an AuthenticatedUser. */ |
| public static final String AUTHUSER = "authenticatedUser"; |
| |
| /** If on the client - this is the Call object. */ |
| public static final String CALL = "call_object" ; |
| |
| /** Are we doing Msg vs RPC? - For Java Binding. */ |
| public static final String IS_MSG = "isMsg" ; |
| |
| /** The directory where in coming attachments are created. */ |
| public static final String ATTACHMENTS_DIR = "attachments.directory" ; |
| |
| /** A boolean param, to control whether we accept missing parameters |
| * as nulls or refuse to acknowledge them. |
| */ |
| public final static String ACCEPTMISSINGPARAMS = "acceptMissingParams"; |
| |
| /** The value of the property is used by service WSDL generation (aka ?WSDL) |
| * For the service's interface namespace if not set TRANS_URL property is used. |
| */ |
| public static final String WSDLGEN_INTFNAMESPACE = "axis.wsdlgen.intfnamespace"; |
| |
| /** The value of the property is used by service WSDL generation (aka ?WSDL). |
| * For the service's location if not set TRANS_URL property is used. |
| * (helps provide support through proxies. |
| */ |
| public static final String WSDLGEN_SERV_LOC_URL = "axis.wsdlgen.serv.loc.url"; |
| |
| // fixme: should this be a type-safe e-num? |
| /** The value of the property is used by service WSDL generation (aka ?WSDL). |
| * Set this property to request a certain level of HTTP. |
| * The values MUST use org.apache.axis.transport.http.HTTPConstants.HEADER_PROTOCOL_10 |
| * for HTTP 1.0 |
| * The values MUST use org.apache.axis.transport.http.HTTPConstants.HEADER_PROTOCOL_11 |
| * for HTTP 1.1 |
| */ |
| public static final String HTTP_TRANSPORT_VERSION = "axis.transport.version"; |
| |
| // fixme: is this the name of a security provider, or the name of a security |
| // provider class, or the actualy class of a security provider, or |
| // something else? |
| /** |
| * The security provider. |
| */ |
| public static final String SECURITY_PROVIDER = "securityProvider"; |
| |
| /* |
| * IMPORTANT. |
| * If adding any new constants to this class. Make them final. The |
| * ones above are left non-final for compatibility reasons. |
| */ |
| |
| /** |
| * Get a <code>String</code> property by name. |
| * |
| * @param propName the name of the property to fetch |
| * @return the value of the named property |
| * @throws ClassCastException if the property named does not have a |
| * <code>String</code> value |
| */ |
| public String getStrProp(String propName) { |
| return (String) getProperty(propName); |
| } |
| |
| /** |
| * Tests to see if the named property is set in the 'bag', returning |
| * <code>false</code> if it is not present at all. |
| * This is equivalent to <code>isPropertyTrue(propName, false)</code>. |
| * |
| * @param propName the name of the property to check |
| * @return true or false, depending on the value of the property |
| */ |
| public boolean isPropertyTrue(String propName) { |
| return isPropertyTrue(propName, false); |
| } |
| |
| /** |
| * Test if a property is set to something we consider to be true in the |
| * 'bag'. |
| * <ul> |
| * <li>If not there then <code>defaultVal</code> is returned.</li> |
| * <li>If there, then...<ul> |
| * <li>if its a <code>Boolean</code>, we'll return booleanValue()</li> |
| * <li>if its an <code>Integer</code>, we'll return <code>false</code> |
| * if its <code>0</code> else <code>true</code></li> |
| * <li>if its a <code>String</code> we'll return <code>false</code> if its |
| * <code>"false"</code>" or <code>"0"</code> else <code>true</code></li> |
| * <li>All other types return <code>true</code></li> |
| * </ul></li> |
| * </ul> |
| * |
| * @param propName the name of the property to check |
| * @param defaultVal the default value |
| * @return true or false, depending on the value of the property |
| */ |
| public boolean isPropertyTrue(String propName, boolean defaultVal) { |
| return JavaUtils.isTrue(getProperty(propName), defaultVal); |
| } |
| |
| /** |
| * Allows you to set a named property to the passed in value. |
| * There are a few known properties (like username, password, etc) |
| * that are variables in Call. The rest of the properties are |
| * stored in a Hashtable. These common properties should be |
| * accessed via the accessors for speed/type safety, but they may |
| * still be obtained via this method. It's up to one of the |
| * Handlers (or the Axis engine itself) to go looking for |
| * one of them. |
| * |
| * @param name Name of the property |
| * @param value Value of the property |
| */ |
| public void setProperty(String name, Object value) { |
| if (name == null || value == null) { |
| return; |
| // Is this right? Shouldn't we throw an exception like: |
| // throw new IllegalArgumentException(msg); |
| } |
| else if (name.equals(Call.USERNAME_PROPERTY)) { |
| if (!(value instanceof String)) { |
| throw new IllegalArgumentException( |
| Messages.getMessage("badProp00", new String[] { |
| name, "java.lang.String", value.getClass().getName()})); |
| } |
| setUsername((String) value); |
| } |
| else if (name.equals(Call.PASSWORD_PROPERTY)) { |
| if (!(value instanceof String)) { |
| throw new IllegalArgumentException( |
| Messages.getMessage("badProp00", new String[] { |
| name, "java.lang.String", value.getClass().getName()})); |
| } |
| setPassword((String) value); |
| } |
| else if (name.equals(Call.SESSION_MAINTAIN_PROPERTY)) { |
| if (!(value instanceof Boolean)) { |
| throw new IllegalArgumentException( |
| Messages.getMessage("badProp00", new String[] |
| {name, |
| "java.lang.Boolean", |
| value.getClass().getName()})); |
| } |
| setMaintainSession(((Boolean) value).booleanValue()); |
| } |
| else if (name.equals(Call.SOAPACTION_USE_PROPERTY)) { |
| if (!(value instanceof Boolean)) { |
| throw new IllegalArgumentException( |
| Messages.getMessage("badProp00", new String[] |
| {name, |
| "java.lang.Boolean", |
| value.getClass().getName()})); |
| } |
| setUseSOAPAction(((Boolean) value).booleanValue()); |
| } |
| else if (name.equals(Call.SOAPACTION_URI_PROPERTY)) { |
| if (!(value instanceof String)) { |
| throw new IllegalArgumentException( |
| Messages.getMessage("badProp00", new String[] |
| {name, |
| "java.lang.String", |
| value.getClass().getName()})); |
| } |
| setSOAPActionURI((String) value); |
| } |
| else if (name.equals(Call.ENCODINGSTYLE_URI_PROPERTY)) { |
| if (!(value instanceof String)) { |
| throw new IllegalArgumentException( |
| Messages.getMessage("badProp00", new String[] |
| {name, |
| "java.lang.String", |
| value.getClass().getName()})); |
| } |
| setEncodingStyle((String) value); |
| } |
| else { |
| bag.put(name, value); |
| } |
| } // setProperty |
| |
| /** |
| * Returns true if the MessageContext contains a property with the specified name. |
| * @param name Name of the property whose presense is to be tested |
| * @return Returns true if the MessageContext contains the |
| property; otherwise false |
| */ |
| public boolean containsProperty(String name) { |
| Object propertyValue = getProperty(name); |
| return (propertyValue != null); |
| } |
| |
| /** |
| * Returns an <code>Iterator</code> view of the names of the properties in |
| * this <code>MessageContext</code>. |
| * |
| * @return an <code>Iterator</code> over all property names |
| */ |
| public java.util.Iterator getPropertyNames() { |
| // fixme: this is potentially unsafe for the caller - changing the |
| // properties will kill the iterator. Consider iterating over a copy: |
| // return new HashSet(bag.keySet()).iterator(); |
| return bag.keySet().iterator(); |
| } |
| |
| /** |
| * Returns an Iterator view of the names of the properties |
| * in this MessageContext and any parents of the LockableHashtable |
| * @return Iterator for the property names |
| */ |
| public java.util.Iterator getAllPropertyNames() { |
| return bag.getAllKeys().iterator(); |
| } |
| |
| /** |
| * Returns the value associated with the named property - or null if not |
| * defined/set. |
| * |
| * @param name the property name |
| * @return Object value of the property - or null |
| */ |
| public Object getProperty(String name) { |
| if (name != null) { |
| if (name.equals(Call.USERNAME_PROPERTY)) { |
| return getUsername(); |
| } |
| else if (name.equals(Call.PASSWORD_PROPERTY)) { |
| return getPassword(); |
| } |
| else if (name.equals(Call.SESSION_MAINTAIN_PROPERTY)) { |
| return getMaintainSession() ? Boolean.TRUE : Boolean.FALSE; |
| } |
| else if (name.equals(Call.OPERATION_STYLE_PROPERTY)) { |
| return (getOperationStyle() == null) ? null : getOperationStyle().getName(); |
| } |
| else if (name.equals(Call.SOAPACTION_USE_PROPERTY)) { |
| return useSOAPAction() ? Boolean.TRUE : Boolean.FALSE; |
| } |
| else if (name.equals(Call.SOAPACTION_URI_PROPERTY)) { |
| return getSOAPActionURI(); |
| } |
| else if (name.equals(Call.ENCODINGSTYLE_URI_PROPERTY)) { |
| return getEncodingStyle(); |
| } |
| else if (bag == null) { |
| return null; |
| } |
| else { |
| return bag.get(name); |
| } |
| } |
| else { |
| return null; |
| } |
| } |
| |
| // fixme: this makes no copy of parent, so later modifications to parent |
| // can alter this context - is this intended? If so, it needs documenting. |
| // If not, it needs fixing. |
| /** |
| * Set the Hashtable that contains the default values for our |
| * properties. |
| * |
| * @param parent |
| */ |
| public void setPropertyParent(Hashtable parent) |
| { |
| bag.setParent(parent); |
| } |
| |
| /** |
| * Set the username. |
| * |
| * @param username the new user name |
| */ |
| public void setUsername(String username) { |
| this.username = username; |
| } // setUsername |
| |
| /** |
| * Get the user name. |
| * |
| * @return the user name as a <code>String</code> |
| */ |
| public String getUsername() { |
| return username; |
| } // getUsername |
| |
| /** |
| * Set the password. |
| * |
| * @param password a <code>String</code> containing the new password |
| */ |
| public void setPassword(String password) { |
| this.password = password; |
| } // setPassword |
| |
| /** |
| * Get the password. |
| * |
| * @return the current password <code>String</code> |
| */ |
| public String getPassword() { |
| return password; |
| } // getPassword |
| |
| /** |
| * Get the operation style. This is either the style of the current |
| * operation or if that is not set, the style of the service handler, or |
| * if that is not set, <code>Style.RPC</code>. |
| * |
| * @return the <code>Style</code> of this message |
| */ |
| public Style getOperationStyle() { |
| if (currentOperation != null) { |
| return currentOperation.getStyle(); |
| } |
| |
| if (serviceHandler != null) { |
| return serviceHandler.getStyle(); |
| } |
| |
| return Style.RPC; |
| } // getOperationStyle |
| |
| /** |
| * Get the operation use. |
| * |
| * @return the operation <code>Use</code> |
| */ |
| public Use getOperationUse() { |
| if (currentOperation != null) { |
| return currentOperation.getUse(); |
| } |
| |
| if (serviceHandler != null) { |
| return serviceHandler.getUse(); |
| } |
| |
| return Use.ENCODED; |
| } // getOperationUse |
| |
| /** |
| * Enable or dissable the use of soap action information. When enabled, |
| * the message context will attempt to use the soap action URI |
| * information during binding of soap messages to service methods. When |
| * dissabled, it will make no such attempt. |
| * |
| * @param useSOAPAction <code>true</code> if soap action URI information |
| * should be used, <code>false</code> otherwise |
| */ |
| public void setUseSOAPAction(boolean useSOAPAction) { |
| this.useSOAPAction = useSOAPAction; |
| } // setUseSOAPAction |
| |
| // fixme: this doesn't follow beany naming conventions - should be |
| // isUseSOAPActions or getUseSOAPActions or something prettier |
| /** |
| * Indicates wether the soap action URI is being used or not. |
| * |
| * @return <code>true</code> if it is, <code>false</code> otherwise |
| */ |
| public boolean useSOAPAction() { |
| return useSOAPAction; |
| } // useSOAPAction |
| |
| // fixme: this throws IllegalArgumentException but never raises it - |
| // perhaps in a sub-class? |
| // fixme: IllegalArgumentException is unchecked. Best practice says you |
| // should document unchecked exceptions, but not list them in throws |
| /** |
| * Set the soapAction URI. |
| * |
| * @param SOAPActionURI a <code>String</code> giving the new soap action |
| * URI |
| * @throws IllegalArgumentException if the URI is not liked |
| */ |
| public void setSOAPActionURI(String SOAPActionURI) |
| throws IllegalArgumentException { |
| this.SOAPActionURI = SOAPActionURI; |
| } // setSOAPActionURI |
| |
| /** |
| * Get the soapAction URI. |
| * |
| * @return the URI of this soap action |
| */ |
| public String getSOAPActionURI() { |
| return SOAPActionURI; |
| } // getSOAPActionURI |
| |
| /** |
| * Sets the encoding style to the URI passed in. |
| * |
| * @param namespaceURI URI of the encoding to use. |
| */ |
| public void setEncodingStyle(String namespaceURI) { |
| if (namespaceURI == null) { |
| namespaceURI = Constants.URI_LITERAL_ENC; |
| } |
| else if (Constants.isSOAP_ENC(namespaceURI)) { |
| namespaceURI = soapConstants.getEncodingURI(); |
| } |
| |
| encodingStyle = namespaceURI; |
| } // setEncodingStype |
| |
| /** |
| * Returns the encoding style as a URI that should be used for the SOAP |
| * message. |
| * |
| * @return String URI of the encoding style to use |
| */ |
| public String getEncodingStyle() { |
| return encodingStyle; |
| } // getEncodingStyle |
| |
| public void removeProperty(String propName) |
| { |
| if (bag != null) { |
| bag.remove(propName); |
| } |
| } |
| |
| /** |
| * Return this context to a clean state. |
| */ |
| public void reset() |
| { |
| if (bag != null) { |
| bag.clear(); |
| } |
| serviceHandler = null; |
| havePassedPivot = false; |
| currentOperation = null; |
| } |
| |
| /** |
| * Read the high fidelity property. |
| * <p> |
| * Some behavior may be apropreate for high fidelity contexts that is not |
| * relevant for low fidelity ones or vica-versa. |
| * |
| * @return <code>true</code> if the context is high fidelity, |
| * <code>false</code> otherwise |
| */ |
| public boolean isHighFidelity() { |
| return highFidelity; |
| } |
| |
| /** |
| * Set the high fidelity propert. |
| * <p> |
| * Users of the context may be changing what they do based upon this flag. |
| * |
| * @param highFidelity the new value of the highFidelity property |
| */ |
| public void setHighFidelity(boolean highFidelity) { |
| this.highFidelity = highFidelity; |
| } |
| |
| /** |
| * Gets the SOAP actor roles associated with an execution of the |
| * <code>HandlerChain</code> and its contained <code>Handler</code> |
| * instances. |
| * <p> |
| * <i>Not (yet) implemented method in the SOAPMessageContext interface</i>. |
| * <p> |
| * <b>Note:</b> SOAP actor roles apply to the SOAP node and are managed |
| * using <code>HandlerChain.setRoles()</code> and |
| * <code>HandlerChain.getRoles()</code>. Handler instances in the |
| * <code>HandlerChain</code> use this information about the SOAP actor roles |
| * to process the SOAP header blocks. Note that the SOAP actor roles are |
| * invariant during the processing of SOAP message through the |
| * <code>HandlerChain</code>. |
| * |
| * @return an array of URIs for SOAP actor roles |
| * @see javax.xml.rpc.handler.HandlerChain#setRoles(java.lang.String[]) HandlerChain.setRoles(java.lang.String[]) |
| * @see javax.xml.rpc.handler.HandlerChain#getRoles() HandlerChain.getRoles() |
| */ |
| public String[] getRoles() { |
| //TODO: Flesh this out. |
| return roles; |
| } |
| |
| /** |
| * Set the SOAP actor roles associated with an executioni of |
| * <code>CodeHandlerChain</code> and its contained <code>Handler</code> |
| * instances. |
| * |
| * @param roles an array of <code>String</code> instances, each representing |
| * the URI for a SOAP actor role |
| */ |
| public void setRoles( String[] roles) { |
| this.roles = roles; |
| } |
| |
| /** |
| * if a message (or subclass) has any disposal needs, this method |
| * is where it goes. Subclasses *must* call super.dispose(), and |
| * be prepared to be called from the finalizer as well as earlier |
| */ |
| public synchronized void dispose() { |
| log.debug("disposing of message context"); |
| if(requestMessage!=null) { |
| requestMessage.dispose(); |
| requestMessage=null; |
| } |
| if(responseMessage!=null) { |
| responseMessage.dispose(); |
| responseMessage=null; |
| } |
| } |
| } |