| /* |
| * 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.components.logger.LogFactory; |
| import org.apache.axis.encoding.TypeMappingRegistry; |
| import org.apache.axis.encoding.TypeMappingImpl; |
| import org.apache.axis.handlers.BasicHandler; |
| import org.apache.axis.handlers.soap.SOAPService; |
| import org.apache.axis.session.Session; |
| import org.apache.axis.session.SimpleSession; |
| import org.apache.axis.utils.JavaUtils; |
| import org.apache.axis.utils.Messages; |
| import org.apache.axis.utils.cache.ClassCache; |
| import org.apache.commons.logging.Log; |
| |
| import javax.xml.namespace.QName; |
| import javax.xml.rpc.server.ServiceLifecycle; |
| import java.util.ArrayList; |
| import java.util.Enumeration; |
| import java.util.Hashtable; |
| |
| |
| /** |
| * An <code>AxisEngine</code> is the base class for AxisClient and |
| * AxisServer. Handles common functionality like dealing with the |
| * handler/service registries and loading properties. |
| * |
| * @author Glen Daniels (gdaniels@apache.org) |
| * @author Glyn Normington (glyn@apache.org) |
| */ |
| public abstract class AxisEngine extends BasicHandler |
| { |
| /** |
| * The <code>Log</code> for all message logging. |
| */ |
| protected static Log log = |
| LogFactory.getLog(AxisEngine.class.getName()); |
| |
| // Engine property names |
| public static final String PROP_XML_DECL = "sendXMLDeclaration"; |
| public static final String PROP_DEBUG_LEVEL = "debugLevel"; |
| public static final String PROP_DEBUG_FILE = "debugFile"; |
| public static final String PROP_DOMULTIREFS = "sendMultiRefs"; |
| public static final String PROP_DISABLE_PRETTY_XML = "disablePrettyXML"; |
| public static final String PROP_ENABLE_NAMESPACE_PREFIX_OPTIMIZATION = "enableNamespacePrefixOptimization"; |
| public static final String PROP_PASSWORD = "adminPassword"; |
| public static final String PROP_SYNC_CONFIG = "syncConfiguration"; |
| public static final String PROP_SEND_XSI = "sendXsiTypes"; |
| public static final String PROP_ATTACHMENT_DIR = "attachments.Directory"; |
| public static final String PROP_ATTACHMENT_IMPLEMENTATION = "attachments.implementation" ; |
| public static final String PROP_ATTACHMENT_CLEANUP = "attachment.DirectoryCleanUp"; |
| public static final String PROP_DEFAULT_CONFIG_CLASS = "axis.engineConfigClass"; |
| public static final String PROP_SOAP_VERSION = "defaultSOAPVersion"; |
| public static final String PROP_SOAP_ALLOWED_VERSION = "singleSOAPVersion"; |
| public static final String PROP_TWOD_ARRAY_ENCODING = "enable2DArrayEncoding"; |
| public static final String PROP_XML_ENCODING = "axis.xmlEncoding"; |
| public static final String PROP_XML_REUSE_SAX_PARSERS = "axis.xml.reuseParsers"; |
| public static final String PROP_BYTE_BUFFER_BACKING = "axis.byteBuffer.backing"; |
| public static final String PROP_BYTE_BUFFER_CACHE_INCREMENT = "axis.byteBuffer.cacheIncrement"; |
| public static final String PROP_BYTE_BUFFER_RESIDENT_MAX_SIZE = "axis.byteBuffer.residentMaxSize"; |
| public static final String PROP_BYTE_BUFFER_WORK_BUFFER_SIZE = "axis.byteBuffer.workBufferSize"; |
| public static final String PROP_EMIT_ALL_TYPES = "emitAllTypesInWSDL"; |
| /** |
| * Set this property to 'true' when you want Axis to avoid soap encoded |
| * types to work around a .NET problem where it wont accept soap encoded |
| * types for a (soap encoded!) array. |
| */ |
| public static final String PROP_DOTNET_SOAPENC_FIX = "dotNetSoapEncFix"; |
| /** Compliance with WS-I Basic Profile. */ |
| public static final String PROP_BP10_COMPLIANCE = "ws-i.bp10Compliance"; |
| |
| public static final String DEFAULT_ATTACHMENT_IMPL="org.apache.axis.attachments.AttachmentsImpl"; |
| |
| public static final String ENV_ATTACHMENT_DIR = "axis.attachments.Directory"; |
| public static final String ENV_SERVLET_REALPATH = "servlet.realpath"; |
| public static final String ENV_SERVLET_CONTEXT = "servletContext"; |
| |
| // Default admin. password |
| private static final String DEFAULT_ADMIN_PASSWORD = "admin"; |
| |
| |
| /** Our go-to guy for configuration... */ |
| protected EngineConfiguration config; |
| |
| /** Has the user changed the password yet? True if they have. */ |
| protected boolean _hasSafePassword = false; |
| |
| /** |
| * Should we save the engine config each time we modify it? True if we |
| * should. |
| */ |
| protected boolean shouldSaveConfig = false; |
| |
| /** Java class cache. */ |
| protected transient ClassCache classCache = new ClassCache(); |
| |
| /** |
| * This engine's Session. This Session supports "application scope" |
| * in the Apache SOAP sense... if you have a service with "application |
| * scope", have it store things in this Session. |
| */ |
| private Session session = new SimpleSession(); |
| |
| /** |
| * What actor URIs hold for the entire engine? Find them here. |
| */ |
| private ArrayList actorURIs = new ArrayList(); |
| |
| /** |
| * Thread local storage used for locating the active message context. |
| * This information is only valid for the lifetime of this request. |
| */ |
| private static ThreadLocal currentMessageContext = new ThreadLocal(); |
| |
| /** |
| * Set the active message context. |
| * |
| * @param mc - the new active message context. |
| */ |
| protected static void setCurrentMessageContext(MessageContext mc) { |
| currentMessageContext.set(mc); |
| } |
| |
| /** |
| * Get the active message context. |
| * |
| * @return the current active message context |
| */ |
| public static MessageContext getCurrentMessageContext() { |
| return (MessageContext) currentMessageContext.get(); |
| } |
| |
| /** |
| * Construct an AxisEngine using the specified engine configuration. |
| * |
| * @param config the EngineConfiguration for this engine |
| */ |
| public AxisEngine(EngineConfiguration config) |
| { |
| this.config = config; |
| init(); |
| } |
| |
| /** |
| * Initialize the engine. Multiple calls will (may?) return the engine to |
| * the intialized state. |
| */ |
| public void init() { |
| if (log.isDebugEnabled()) { |
| log.debug("Enter: AxisEngine::init"); |
| } |
| |
| // The SOAP/XSD stuff is in the default TypeMapping of the TypeMappingRegistry. |
| //getTypeMappingRegistry().setParent(SOAPTypeMappingRegistry.getSingletonDelegate()); |
| |
| try { |
| config.configureEngine(this); |
| } catch (Exception e) { |
| throw new InternalException(e); |
| } |
| |
| /*Set the default attachment implementation */ |
| setOptionDefault(PROP_ATTACHMENT_IMPLEMENTATION, |
| AxisProperties.getProperty("axis." + PROP_ATTACHMENT_IMPLEMENTATION )); |
| |
| setOptionDefault(PROP_ATTACHMENT_IMPLEMENTATION, DEFAULT_ATTACHMENT_IMPL); |
| |
| // Check for the property "dotnetsoapencfix" which will turn |
| // off soap encoded types to work around a bug in .NET where |
| // it wont accept soap encoded array types. |
| final Object dotnet = getOption(PROP_DOTNET_SOAPENC_FIX); |
| if (JavaUtils.isTrue(dotnet)) { |
| // This is a static property of the type mapping |
| // that will ignore SOAPENC types when looking up |
| // QNames of java types. |
| TypeMappingImpl.dotnet_soapenc_bugfix = true; |
| } |
| |
| if (log.isDebugEnabled()) { |
| log.debug("Exit: AxisEngine::init"); |
| } |
| |
| } |
| |
| /** |
| * Cleanup routine removes application scoped objects. |
| * |
| * There is a small risk of this being called more than once |
| * so the cleanup should be designed to resist that event. |
| */ |
| public void cleanup() { |
| super.cleanup(); |
| |
| // Let any application-scoped service objects know that we're going |
| // away... |
| Enumeration keys = session.getKeys(); |
| if (keys != null) { |
| while (keys.hasMoreElements()) { |
| String key = (String)keys.nextElement(); |
| Object obj = session.get(key); |
| if (obj != null && obj instanceof ServiceLifecycle) { |
| ((ServiceLifecycle)obj).destroy(); |
| } |
| session.remove(key); |
| } |
| } |
| } |
| |
| /** Write out our engine configuration. |
| */ |
| public void saveConfiguration() |
| { |
| if (!shouldSaveConfig) |
| return; |
| |
| try { |
| config.writeEngineConfig(this); |
| } catch (Exception e) { |
| log.error(Messages.getMessage("saveConfigFail00"), e); |
| } |
| } |
| |
| /** |
| * Get the <code>EngineConfiguration</code> used throughout this |
| * <code>AxisEngine</code> instance. |
| * |
| * @return the engine configuration instance |
| */ |
| public EngineConfiguration getConfig() { |
| return config; |
| } |
| |
| /** |
| * Discover if this <code>AxisEngine</code> has a safe password. |
| * |
| * @return true if it is safe, false otherwise |
| */ |
| public boolean hasSafePassword() |
| { |
| return _hasSafePassword; |
| } |
| |
| /** |
| * Set the administration password. |
| * |
| * @param pw the literal value of the password as a <code>String</code> |
| */ |
| public void setAdminPassword(String pw) |
| { |
| setOption(PROP_PASSWORD, pw); |
| _hasSafePassword = true; |
| saveConfiguration(); |
| } |
| |
| /** |
| * Set the flag that controls if the configuration should be saved. |
| * |
| * @param shouldSaveConfig true if the configuration should be changed, |
| * false otherwise |
| */ |
| public void setShouldSaveConfig(boolean shouldSaveConfig) |
| { |
| this.shouldSaveConfig = shouldSaveConfig; |
| } |
| |
| // fixme: could someone who knows double-check I've got the semantics of |
| // this right? |
| /** |
| * Get the <code>Handler</code> for a particular local name. |
| * |
| * @param name the local name of the request type |
| * @return the <code>Handler</code> for this request type |
| * @throws AxisFault |
| */ |
| public Handler getHandler(String name) throws AxisFault |
| { |
| try { |
| return config.getHandler(new QName(null, name)); |
| } catch (ConfigurationException e) { |
| throw new AxisFault(e); |
| } |
| } |
| |
| // fixme: could someone who knows double-check I've got the semantics of |
| // this right? |
| /** |
| * Get the <code>SOAPService</code> for a particular local name. |
| * |
| * @param name the local name of the request type |
| * @return the <code>SOAPService</code> for this request type |
| * @throws AxisFault |
| */ |
| public SOAPService getService(String name) throws AxisFault |
| { |
| try { |
| return config.getService(new QName(null, name)); |
| } catch (ConfigurationException e) { |
| try { |
| return config.getServiceByNamespaceURI(name); |
| } catch (ConfigurationException e1) { |
| throw new AxisFault(e); |
| } |
| } |
| } |
| |
| /** |
| * Get the <code>Handler</code> that implements the transport for a local |
| * name. |
| * |
| * @param name the local name to fetch the transport for |
| * @return a <code>Handler</code> for this local name |
| * @throws AxisFault |
| */ |
| public Handler getTransport(String name) throws AxisFault |
| { |
| try { |
| return config.getTransport(new QName(null, name)); |
| } catch (ConfigurationException e) { |
| throw new AxisFault(e); |
| } |
| } |
| |
| /** |
| * Get the <code>TypeMappingRegistry</code> for this axis engine. |
| * |
| * @return the <code>TypeMappingRegistry</code> if possible, or null if |
| * there is any error resolving it |
| */ |
| public TypeMappingRegistry getTypeMappingRegistry() |
| { |
| TypeMappingRegistry tmr = null; |
| try { |
| tmr = config.getTypeMappingRegistry(); |
| } catch (ConfigurationException e) { |
| log.error(Messages.getMessage("axisConfigurationException00"), e); |
| } |
| |
| return tmr; |
| } |
| |
| /** |
| * Get the global request <code>Handler</code>. |
| * |
| * @return the <code>Handler</code> used for global requests |
| * @throws ConfigurationException |
| */ |
| public Handler getGlobalRequest() |
| throws ConfigurationException |
| { |
| return config.getGlobalRequest(); |
| } |
| |
| /** |
| * Get the global respones <code>Handler</code>. |
| * |
| * @return the <code>Handler</code> used for global responses |
| * @throws ConfigurationException |
| */ |
| public Handler getGlobalResponse() |
| throws ConfigurationException |
| { |
| return config.getGlobalResponse(); |
| } |
| |
| // fixme: publishing this as ArrayList prevents us moving to another |
| // List impl later |
| /** |
| * Get a list of actor URIs that hold for the entire engine. |
| * |
| * @return an <code>ArrayList</code> of all actor URIs as |
| * <code>Strings</code> |
| */ |
| public ArrayList getActorURIs() |
| { |
| return (ArrayList)actorURIs.clone(); |
| } |
| |
| /** |
| * Add an actor by uri that will hold for the entire engine. |
| * |
| * @param uri a <code>String</code> giving the uri of the actor to add |
| */ |
| public void addActorURI(String uri) |
| { |
| actorURIs.add(uri); |
| } |
| |
| /** |
| * Remove an actor by uri that will hold for the entire engine. |
| * |
| * @param uri a <code>String</code> giving the uri of the actor to remove |
| */ |
| public void removeActorURI(String uri) |
| { |
| actorURIs.remove(uri); |
| } |
| |
| /** |
| * Client engine access. |
| * <p> |
| * An AxisEngine may define another specific AxisEngine to be used |
| * by newly created Clients. For instance, a server may |
| * create an AxisClient and allow deployment to it. Then |
| * the server's services may access the AxisClient's deployed |
| * handlers and transports. |
| * |
| * @return an <code>AxisEngine</code> that is the client engine |
| */ |
| |
| public abstract AxisEngine getClientEngine (); |
| |
| /** |
| * Administration and management APIs |
| * |
| * These can get called by various admin adapters, such as JMX MBeans, |
| * our own Admin client, web applications, etc... |
| * |
| */ |
| |
| /** |
| * List of options which should be converted from Strings to Booleans |
| * automatically. Note that these options are common to all XML |
| * web services. |
| */ |
| private static final String [] BOOLEAN_OPTIONS = new String [] { |
| PROP_DOMULTIREFS, PROP_SEND_XSI, PROP_XML_DECL, |
| PROP_DISABLE_PRETTY_XML, |
| PROP_ENABLE_NAMESPACE_PREFIX_OPTIMIZATION |
| }; |
| |
| /** |
| * Normalise the engine's options. |
| * <p> |
| * Convert boolean options from String to Boolean and default |
| * any ommitted boolean options to TRUE. Default the admin. |
| * password. |
| * |
| * @param handler the <code>Handler</code> to normalise; instances of |
| * <code>AxisEngine</code> get extra data normalised |
| */ |
| public static void normaliseOptions(Handler handler) { |
| // Convert boolean options to Booleans so we don't need to use |
| // string comparisons. Default is "true". |
| |
| for (int i = 0; i < BOOLEAN_OPTIONS.length; i++) { |
| Object val = handler.getOption(BOOLEAN_OPTIONS[i]); |
| if (val != null) { |
| if (val instanceof Boolean) |
| continue; |
| if (JavaUtils.isFalse(val)) { |
| handler.setOption(BOOLEAN_OPTIONS[i], Boolean.FALSE); |
| continue; |
| } |
| } else { |
| if (!(handler instanceof AxisEngine)) |
| continue; |
| } |
| // If it was null or not "false"... |
| handler.setOption(BOOLEAN_OPTIONS[i], Boolean.TRUE); |
| } |
| |
| // Deal with admin password's default value. |
| if (handler instanceof AxisEngine) { |
| AxisEngine engine = (AxisEngine)handler; |
| if (!engine.setOptionDefault(PROP_PASSWORD, |
| DEFAULT_ADMIN_PASSWORD)) { |
| engine.setAdminPassword( |
| (String)engine.getOption(PROP_PASSWORD)); |
| } |
| } |
| } |
| |
| /** |
| * (Re-)load the global options from the registry. |
| * |
| * @throws ConfigurationException |
| */ |
| public void refreshGlobalOptions() throws ConfigurationException { |
| Hashtable globalOptions = config.getGlobalOptions(); |
| if (globalOptions != null) |
| setOptions(globalOptions); |
| |
| normaliseOptions(this); |
| |
| // fixme: If we change actorURIs to List, this copy constructor can |
| // go away... |
| actorURIs = new ArrayList(config.getRoles()); |
| } |
| |
| /** |
| * Get the <code>Session</code> object associated with the application |
| * session. |
| * |
| * @return a <code>Session</code> scoped to the application |
| */ |
| public Session getApplicationSession () { |
| return session; |
| } |
| |
| /** |
| * Get the <code>ClassCache</code> associated with this engine. |
| * |
| * @return the class cache |
| */ |
| public ClassCache getClassCache() { |
| return classCache; |
| } |
| |
| } |