| /* |
| * 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.catalina.deploy; |
| |
| import java.beans.PropertyChangeListener; |
| import java.beans.PropertyChangeSupport; |
| import java.io.Serializable; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| import javax.naming.NamingException; |
| |
| import org.apache.catalina.Container; |
| import org.apache.catalina.Context; |
| import org.apache.catalina.Engine; |
| import org.apache.catalina.JmxEnabled; |
| import org.apache.catalina.LifecycleException; |
| import org.apache.catalina.LifecycleState; |
| import org.apache.catalina.Server; |
| import org.apache.catalina.mbeans.MBeanUtils; |
| import org.apache.catalina.util.Introspection; |
| import org.apache.catalina.util.LifecycleMBeanBase; |
| import org.apache.juli.logging.Log; |
| import org.apache.juli.logging.LogFactory; |
| import org.apache.naming.ContextBindings; |
| import org.apache.tomcat.util.ExceptionUtils; |
| import org.apache.tomcat.util.descriptor.web.ContextEjb; |
| import org.apache.tomcat.util.descriptor.web.ContextEnvironment; |
| import org.apache.tomcat.util.descriptor.web.ContextLocalEjb; |
| import org.apache.tomcat.util.descriptor.web.ContextResource; |
| import org.apache.tomcat.util.descriptor.web.ContextResourceEnvRef; |
| import org.apache.tomcat.util.descriptor.web.ContextResourceLink; |
| import org.apache.tomcat.util.descriptor.web.ContextService; |
| import org.apache.tomcat.util.descriptor.web.ContextTransaction; |
| import org.apache.tomcat.util.descriptor.web.InjectionTarget; |
| import org.apache.tomcat.util.descriptor.web.MessageDestinationRef; |
| import org.apache.tomcat.util.descriptor.web.NamingResources; |
| import org.apache.tomcat.util.descriptor.web.ResourceBase; |
| import org.apache.tomcat.util.res.StringManager; |
| |
| |
| /** |
| * Holds and manages the naming resources defined in the J2EE Enterprise |
| * Naming Context and their associated JNDI context. |
| * |
| * @author Remy Maucherat |
| */ |
| public class NamingResourcesImpl extends LifecycleMBeanBase |
| implements Serializable, NamingResources { |
| |
| private static final long serialVersionUID = 1L; |
| |
| private static final Log log = LogFactory.getLog(NamingResourcesImpl.class); |
| |
| private static final StringManager sm = |
| StringManager.getManager(Constants.Package); |
| |
| private volatile boolean resourceRequireExplicitRegistration = false; |
| |
| // ----------------------------------------------------------- Constructors |
| |
| |
| /** |
| * Create a new NamingResources instance. |
| */ |
| public NamingResourcesImpl() { |
| // NOOP |
| } |
| |
| |
| // ----------------------------------------------------- Instance Variables |
| |
| |
| /** |
| * Associated container object. |
| */ |
| private Object container = null; |
| |
| |
| /** |
| * Set of naming entries, keyed by name. |
| */ |
| private final Set<String> entries = new HashSet<>(); |
| |
| |
| /** |
| * The EJB resource references for this web application, keyed by name. |
| */ |
| private final HashMap<String, ContextEjb> ejbs = new HashMap<>(); |
| |
| |
| /** |
| * The environment entries for this web application, keyed by name. |
| */ |
| private final HashMap<String, ContextEnvironment> envs = new HashMap<>(); |
| |
| |
| /** |
| * The local EJB resource references for this web application, keyed by |
| * name. |
| */ |
| private final HashMap<String, ContextLocalEjb> localEjbs = new HashMap<>(); |
| |
| |
| /** |
| * The message destination references for this web application, |
| * keyed by name. |
| */ |
| private final HashMap<String, MessageDestinationRef> mdrs = new HashMap<>(); |
| |
| |
| /** |
| * The resource environment references for this web application, |
| * keyed by name. |
| */ |
| private final HashMap<String, ContextResourceEnvRef> resourceEnvRefs = |
| new HashMap<>(); |
| |
| |
| /** |
| * The resource references for this web application, keyed by name. |
| */ |
| private final HashMap<String, ContextResource> resources = |
| new HashMap<>(); |
| |
| |
| /** |
| * The resource links for this web application, keyed by name. |
| */ |
| private final HashMap<String, ContextResourceLink> resourceLinks = |
| new HashMap<>(); |
| |
| |
| /** |
| * The web service references for this web application, keyed by name. |
| */ |
| private final HashMap<String, ContextService> services = |
| new HashMap<>(); |
| |
| |
| /** |
| * The transaction for this webapp. |
| */ |
| private ContextTransaction transaction = null; |
| |
| |
| /** |
| * The property change support for this component. |
| */ |
| protected final PropertyChangeSupport support = |
| new PropertyChangeSupport(this); |
| |
| |
| // ------------------------------------------------------------- Properties |
| |
| |
| /** |
| * Get the container with which the naming resources are associated. |
| */ |
| @Override |
| public Object getContainer() { |
| return container; |
| } |
| |
| |
| /** |
| * Set the container with which the naming resources are associated. |
| */ |
| public void setContainer(Object container) { |
| this.container = container; |
| } |
| |
| |
| /** |
| * Set the transaction object. |
| */ |
| public void setTransaction(ContextTransaction transaction) { |
| this.transaction = transaction; |
| } |
| |
| |
| /** |
| * Get the transaction object. |
| */ |
| public ContextTransaction getTransaction() { |
| return transaction; |
| } |
| |
| |
| /** |
| * Add an EJB resource reference for this web application. |
| * |
| * @param ejb New EJB resource reference |
| */ |
| public void addEjb(ContextEjb ejb) { |
| |
| if (entries.contains(ejb.getName())) { |
| return; |
| } else { |
| entries.add(ejb.getName()); |
| } |
| |
| synchronized (ejbs) { |
| ejb.setNamingResources(this); |
| ejbs.put(ejb.getName(), ejb); |
| } |
| support.firePropertyChange("ejb", null, ejb); |
| |
| } |
| |
| |
| /** |
| * Add an environment entry for this web application. |
| * |
| * @param environment New environment entry |
| */ |
| @Override |
| public void addEnvironment(ContextEnvironment environment) { |
| |
| if (entries.contains(environment.getName())) { |
| ContextEnvironment ce = findEnvironment(environment.getName()); |
| ContextResourceLink rl = findResourceLink(environment.getName()); |
| if (ce != null) { |
| if (ce.getOverride()) { |
| removeEnvironment(environment.getName()); |
| } else { |
| return; |
| } |
| } else if (rl != null) { |
| // Link. Need to look at the global resources |
| NamingResourcesImpl global = getServer().getGlobalNamingResources(); |
| if (global.findEnvironment(rl.getGlobal()) != null) { |
| if (global.findEnvironment(rl.getGlobal()).getOverride()) { |
| removeResourceLink(environment.getName()); |
| } else { |
| return; |
| } |
| } |
| } else { |
| // It exists but it isn't an env or a res link... |
| return; |
| } |
| } |
| |
| // Entries with injection targets but no value are effectively ignored |
| if (environment.getInjectionTargets() != null && environment.getInjectionTargets().size() > 0 && |
| (environment.getValue() == null || environment.getValue().length() == 0)) { |
| return; |
| } |
| |
| if (!checkResourceType(environment)) { |
| throw new IllegalArgumentException(sm.getString( |
| "namingResources.resourceTypeFail", environment.getName(), |
| environment.getType())); |
| } |
| |
| entries.add(environment.getName()); |
| |
| synchronized (envs) { |
| environment.setNamingResources(this); |
| envs.put(environment.getName(), environment); |
| } |
| support.firePropertyChange("environment", null, environment); |
| |
| // Register with JMX |
| if (resourceRequireExplicitRegistration) { |
| try { |
| MBeanUtils.createMBean(environment); |
| } catch (Exception e) { |
| log.warn(sm.getString("namingResources.mbeanCreateFail", |
| environment.getName()), e); |
| } |
| } |
| } |
| |
| // Container should be an instance of Server or Context. If it is anything |
| // else, return null which will trigger a NPE. |
| private Server getServer() { |
| if (container instanceof Server) { |
| return (Server) container; |
| } |
| if (container instanceof Context) { |
| // Could do this in one go. Lots of casts so split out for clarity |
| Engine engine = |
| (Engine) ((Context) container).getParent().getParent(); |
| return engine.getService().getServer(); |
| } |
| return null; |
| } |
| |
| /** |
| * Add a local EJB resource reference for this web application. |
| * |
| * @param ejb New EJB resource reference |
| */ |
| public void addLocalEjb(ContextLocalEjb ejb) { |
| |
| if (entries.contains(ejb.getName())) { |
| return; |
| } else { |
| entries.add(ejb.getName()); |
| } |
| |
| synchronized (localEjbs) { |
| ejb.setNamingResources(this); |
| localEjbs.put(ejb.getName(), ejb); |
| } |
| support.firePropertyChange("localEjb", null, ejb); |
| |
| } |
| |
| |
| /** |
| * Add a message destination reference for this web application. |
| * |
| * @param mdr New message destination reference |
| */ |
| public void addMessageDestinationRef(MessageDestinationRef mdr) { |
| |
| if (entries.contains(mdr.getName())) { |
| return; |
| } else { |
| if (!checkResourceType(mdr)) { |
| throw new IllegalArgumentException(sm.getString( |
| "namingResources.resourceTypeFail", mdr.getName(), |
| mdr.getType())); |
| } |
| entries.add(mdr.getName()); |
| } |
| |
| synchronized (mdrs) { |
| mdr.setNamingResources(this); |
| mdrs.put(mdr.getName(), mdr); |
| } |
| support.firePropertyChange("messageDestinationRef", null, mdr); |
| |
| } |
| |
| |
| /** |
| * Add a property change listener to this component. |
| * |
| * @param listener The listener to add |
| */ |
| public void addPropertyChangeListener(PropertyChangeListener listener) { |
| |
| support.addPropertyChangeListener(listener); |
| |
| } |
| |
| |
| /** |
| * Add a resource reference for this web application. |
| * |
| * @param resource New resource reference |
| */ |
| @Override |
| public void addResource(ContextResource resource) { |
| |
| if (entries.contains(resource.getName())) { |
| return; |
| } else { |
| if (!checkResourceType(resource)) { |
| throw new IllegalArgumentException(sm.getString( |
| "namingResources.resourceTypeFail", resource.getName(), |
| resource.getType())); |
| } |
| entries.add(resource.getName()); |
| } |
| |
| synchronized (resources) { |
| resource.setNamingResources(this); |
| resources.put(resource.getName(), resource); |
| } |
| support.firePropertyChange("resource", null, resource); |
| |
| // Register with JMX |
| if (resourceRequireExplicitRegistration) { |
| try { |
| MBeanUtils.createMBean(resource); |
| } catch (Exception e) { |
| log.warn(sm.getString("namingResources.mbeanCreateFail", |
| resource.getName()), e); |
| } |
| } |
| } |
| |
| |
| /** |
| * Add a resource environment reference for this web application. |
| * |
| * @param resource The resource |
| */ |
| public void addResourceEnvRef(ContextResourceEnvRef resource) { |
| |
| if (entries.contains(resource.getName())) { |
| return; |
| } else { |
| if (!checkResourceType(resource)) { |
| throw new IllegalArgumentException(sm.getString( |
| "namingResources.resourceTypeFail", resource.getName(), |
| resource.getType())); |
| } |
| entries.add(resource.getName()); |
| } |
| |
| synchronized (resourceEnvRefs) { |
| resource.setNamingResources(this); |
| resourceEnvRefs.put(resource.getName(), resource); |
| } |
| support.firePropertyChange("resourceEnvRef", null, resource); |
| |
| } |
| |
| |
| /** |
| * Add a resource link for this web application. |
| * |
| * @param resourceLink New resource link |
| */ |
| @Override |
| public void addResourceLink(ContextResourceLink resourceLink) { |
| |
| if (entries.contains(resourceLink.getName())) { |
| return; |
| } else { |
| entries.add(resourceLink.getName()); |
| } |
| |
| synchronized (resourceLinks) { |
| resourceLink.setNamingResources(this); |
| resourceLinks.put(resourceLink.getName(), resourceLink); |
| } |
| support.firePropertyChange("resourceLink", null, resourceLink); |
| |
| // Register with JMX |
| if (resourceRequireExplicitRegistration) { |
| try { |
| MBeanUtils.createMBean(resourceLink); |
| } catch (Exception e) { |
| log.warn(sm.getString("namingResources.mbeanCreateFail", |
| resourceLink.getName()), e); |
| } |
| } |
| } |
| |
| |
| /** |
| * Add a web service reference for this web application. |
| * |
| * @param service New web service reference |
| */ |
| public void addService(ContextService service) { |
| |
| if (entries.contains(service.getName())) { |
| return; |
| } else { |
| entries.add(service.getName()); |
| } |
| |
| synchronized (services) { |
| service.setNamingResources(this); |
| services.put(service.getName(), service); |
| } |
| support.firePropertyChange("service", null, service); |
| |
| } |
| |
| |
| /** |
| * Return the EJB resource reference with the specified name, if any; |
| * otherwise, return <code>null</code>. |
| * |
| * @param name Name of the desired EJB resource reference |
| */ |
| public ContextEjb findEjb(String name) { |
| |
| synchronized (ejbs) { |
| return ejbs.get(name); |
| } |
| |
| } |
| |
| |
| /** |
| * Return the defined EJB resource references for this application. |
| * If there are none, a zero-length array is returned. |
| */ |
| public ContextEjb[] findEjbs() { |
| |
| synchronized (ejbs) { |
| ContextEjb results[] = new ContextEjb[ejbs.size()]; |
| return ejbs.values().toArray(results); |
| } |
| |
| } |
| |
| |
| /** |
| * Return the environment entry with the specified name, if any; |
| * otherwise, return <code>null</code>. |
| * |
| * @param name Name of the desired environment entry |
| */ |
| public ContextEnvironment findEnvironment(String name) { |
| |
| synchronized (envs) { |
| return envs.get(name); |
| } |
| |
| } |
| |
| |
| /** |
| * Return the set of defined environment entries for this web |
| * application. If none have been defined, a zero-length array |
| * is returned. |
| */ |
| public ContextEnvironment[] findEnvironments() { |
| |
| synchronized (envs) { |
| ContextEnvironment results[] = new ContextEnvironment[envs.size()]; |
| return envs.values().toArray(results); |
| } |
| |
| } |
| |
| |
| /** |
| * Return the local EJB resource reference with the specified name, if any; |
| * otherwise, return <code>null</code>. |
| * |
| * @param name Name of the desired EJB resource reference |
| */ |
| public ContextLocalEjb findLocalEjb(String name) { |
| |
| synchronized (localEjbs) { |
| return localEjbs.get(name); |
| } |
| |
| } |
| |
| |
| /** |
| * Return the defined local EJB resource references for this application. |
| * If there are none, a zero-length array is returned. |
| */ |
| public ContextLocalEjb[] findLocalEjbs() { |
| |
| synchronized (localEjbs) { |
| ContextLocalEjb results[] = new ContextLocalEjb[localEjbs.size()]; |
| return localEjbs.values().toArray(results); |
| } |
| |
| } |
| |
| |
| /** |
| * Return the message destination reference with the specified name, |
| * if any; otherwise, return <code>null</code>. |
| * |
| * @param name Name of the desired message destination reference |
| */ |
| public MessageDestinationRef findMessageDestinationRef(String name) { |
| |
| synchronized (mdrs) { |
| return mdrs.get(name); |
| } |
| |
| } |
| |
| |
| /** |
| * Return the defined message destination references for this application. |
| * If there are none, a zero-length array is returned. |
| */ |
| public MessageDestinationRef[] findMessageDestinationRefs() { |
| |
| synchronized (mdrs) { |
| MessageDestinationRef results[] = |
| new MessageDestinationRef[mdrs.size()]; |
| return mdrs.values().toArray(results); |
| } |
| |
| } |
| |
| |
| /** |
| * Return the resource reference with the specified name, if any; |
| * otherwise return <code>null</code>. |
| * |
| * @param name Name of the desired resource reference |
| */ |
| public ContextResource findResource(String name) { |
| |
| synchronized (resources) { |
| return resources.get(name); |
| } |
| |
| } |
| |
| |
| /** |
| * Return the resource link with the specified name, if any; |
| * otherwise return <code>null</code>. |
| * |
| * @param name Name of the desired resource link |
| */ |
| public ContextResourceLink findResourceLink(String name) { |
| |
| synchronized (resourceLinks) { |
| return resourceLinks.get(name); |
| } |
| |
| } |
| |
| |
| /** |
| * Return the defined resource links for this application. If |
| * none have been defined, a zero-length array is returned. |
| */ |
| public ContextResourceLink[] findResourceLinks() { |
| |
| synchronized (resourceLinks) { |
| ContextResourceLink results[] = |
| new ContextResourceLink[resourceLinks.size()]; |
| return resourceLinks.values().toArray(results); |
| } |
| |
| } |
| |
| |
| /** |
| * Return the defined resource references for this application. If |
| * none have been defined, a zero-length array is returned. |
| */ |
| public ContextResource[] findResources() { |
| |
| synchronized (resources) { |
| ContextResource results[] = new ContextResource[resources.size()]; |
| return resources.values().toArray(results); |
| } |
| |
| } |
| |
| |
| /** |
| * Return the resource environment reference type for the specified |
| * name, if any; otherwise return <code>null</code>. |
| * |
| * @param name Name of the desired resource environment reference |
| */ |
| public ContextResourceEnvRef findResourceEnvRef(String name) { |
| |
| synchronized (resourceEnvRefs) { |
| return resourceEnvRefs.get(name); |
| } |
| |
| } |
| |
| |
| /** |
| * Return the set of resource environment reference names for this |
| * web application. If none have been specified, a zero-length |
| * array is returned. |
| */ |
| public ContextResourceEnvRef[] findResourceEnvRefs() { |
| |
| synchronized (resourceEnvRefs) { |
| ContextResourceEnvRef results[] = new ContextResourceEnvRef[resourceEnvRefs.size()]; |
| return resourceEnvRefs.values().toArray(results); |
| } |
| |
| } |
| |
| |
| /** |
| * Return the web service reference for the specified |
| * name, if any; otherwise return <code>null</code>. |
| * |
| * @param name Name of the desired web service |
| */ |
| public ContextService findService(String name) { |
| |
| synchronized (services) { |
| return services.get(name); |
| } |
| |
| } |
| |
| |
| /** |
| * Return the defined web service references for this application. If |
| * none have been defined, a zero-length array is returned. |
| */ |
| public ContextService[] findServices() { |
| |
| synchronized (services) { |
| ContextService results[] = new ContextService[services.size()]; |
| return services.values().toArray(results); |
| } |
| |
| } |
| |
| |
| /** |
| * Remove any EJB resource reference with the specified name. |
| * |
| * @param name Name of the EJB resource reference to remove |
| */ |
| public void removeEjb(String name) { |
| |
| entries.remove(name); |
| |
| ContextEjb ejb = null; |
| synchronized (ejbs) { |
| ejb = ejbs.remove(name); |
| } |
| if (ejb != null) { |
| support.firePropertyChange("ejb", ejb, null); |
| ejb.setNamingResources(null); |
| } |
| |
| } |
| |
| |
| /** |
| * Remove any environment entry with the specified name. |
| * |
| * @param name Name of the environment entry to remove |
| */ |
| @Override |
| public void removeEnvironment(String name) { |
| |
| entries.remove(name); |
| |
| ContextEnvironment environment = null; |
| synchronized (envs) { |
| environment = envs.remove(name); |
| } |
| if (environment != null) { |
| support.firePropertyChange("environment", environment, null); |
| // De-register with JMX |
| if (resourceRequireExplicitRegistration) { |
| try { |
| MBeanUtils.destroyMBean(environment); |
| } catch (Exception e) { |
| log.warn(sm.getString("namingResources.mbeanDestroyFail", |
| environment.getName()), e); |
| } |
| } |
| environment.setNamingResources(null); |
| } |
| } |
| |
| |
| /** |
| * Remove any local EJB resource reference with the specified name. |
| * |
| * @param name Name of the EJB resource reference to remove |
| */ |
| public void removeLocalEjb(String name) { |
| |
| entries.remove(name); |
| |
| ContextLocalEjb localEjb = null; |
| synchronized (localEjbs) { |
| localEjb = localEjbs.remove(name); |
| } |
| if (localEjb != null) { |
| support.firePropertyChange("localEjb", localEjb, null); |
| localEjb.setNamingResources(null); |
| } |
| |
| } |
| |
| |
| /** |
| * Remove any message destination reference with the specified name. |
| * |
| * @param name Name of the message destination resource reference to remove |
| */ |
| public void removeMessageDestinationRef(String name) { |
| |
| entries.remove(name); |
| |
| MessageDestinationRef mdr = null; |
| synchronized (mdrs) { |
| mdr = mdrs.remove(name); |
| } |
| if (mdr != null) { |
| support.firePropertyChange("messageDestinationRef", |
| mdr, null); |
| mdr.setNamingResources(null); |
| } |
| |
| } |
| |
| |
| /** |
| * Remove a property change listener from this component. |
| * |
| * @param listener The listener to remove |
| */ |
| public void removePropertyChangeListener(PropertyChangeListener listener) { |
| |
| support.removePropertyChangeListener(listener); |
| |
| } |
| |
| |
| /** |
| * Remove any resource reference with the specified name. |
| * |
| * @param name Name of the resource reference to remove |
| */ |
| @Override |
| public void removeResource(String name) { |
| |
| entries.remove(name); |
| |
| ContextResource resource = null; |
| synchronized (resources) { |
| resource = resources.remove(name); |
| } |
| if (resource != null) { |
| support.firePropertyChange("resource", resource, null); |
| // De-register with JMX |
| if (resourceRequireExplicitRegistration) { |
| try { |
| MBeanUtils.destroyMBean(resource); |
| } catch (Exception e) { |
| log.warn(sm.getString("namingResources.mbeanDestroyFail", |
| resource.getName()), e); |
| } |
| } |
| resource.setNamingResources(null); |
| } |
| } |
| |
| |
| /** |
| * Remove any resource environment reference with the specified name. |
| * |
| * @param name Name of the resource environment reference to remove |
| */ |
| public void removeResourceEnvRef(String name) { |
| |
| entries.remove(name); |
| |
| ContextResourceEnvRef resourceEnvRef = null; |
| synchronized (resourceEnvRefs) { |
| resourceEnvRef = |
| resourceEnvRefs.remove(name); |
| } |
| if (resourceEnvRef != null) { |
| support.firePropertyChange("resourceEnvRef", resourceEnvRef, null); |
| resourceEnvRef.setNamingResources(null); |
| } |
| |
| } |
| |
| |
| /** |
| * Remove any resource link with the specified name. |
| * |
| * @param name Name of the resource link to remove |
| */ |
| @Override |
| public void removeResourceLink(String name) { |
| |
| entries.remove(name); |
| |
| ContextResourceLink resourceLink = null; |
| synchronized (resourceLinks) { |
| resourceLink = resourceLinks.remove(name); |
| } |
| if (resourceLink != null) { |
| support.firePropertyChange("resourceLink", resourceLink, null); |
| // De-register with JMX |
| if (resourceRequireExplicitRegistration) { |
| try { |
| MBeanUtils.destroyMBean(resourceLink); |
| } catch (Exception e) { |
| log.warn(sm.getString("namingResources.mbeanDestroyFail", |
| resourceLink.getName()), e); |
| } |
| } |
| resourceLink.setNamingResources(null); |
| } |
| } |
| |
| |
| /** |
| * Remove any web service reference with the specified name. |
| * |
| * @param name Name of the web service reference to remove |
| */ |
| public void removeService(String name) { |
| |
| entries.remove(name); |
| |
| ContextService service = null; |
| synchronized (services) { |
| service = services.remove(name); |
| } |
| if (service != null) { |
| support.firePropertyChange("service", service, null); |
| service.setNamingResources(null); |
| } |
| |
| } |
| |
| |
| // ------------------------------------------------------- Lifecycle methods |
| |
| @Override |
| protected void initInternal() throws LifecycleException { |
| super.initInternal(); |
| |
| // Set this before we register currently known naming resources to avoid |
| // timing issues. Duplication registration is not an issue. |
| resourceRequireExplicitRegistration = true; |
| |
| for (ContextResource cr : resources.values()) { |
| try { |
| MBeanUtils.createMBean(cr); |
| } catch (Exception e) { |
| log.warn(sm.getString( |
| "namingResources.mbeanCreateFail", cr.getName()), e); |
| } |
| } |
| |
| for (ContextEnvironment ce : envs.values()) { |
| try { |
| MBeanUtils.createMBean(ce); |
| } catch (Exception e) { |
| log.warn(sm.getString( |
| "namingResources.mbeanCreateFail", ce.getName()), e); |
| } |
| } |
| |
| for (ContextResourceLink crl : resourceLinks.values()) { |
| try { |
| MBeanUtils.createMBean(crl); |
| } catch (Exception e) { |
| log.warn(sm.getString( |
| "namingResources.mbeanCreateFail", crl.getName()), e); |
| } |
| } |
| } |
| |
| |
| @Override |
| protected void startInternal() throws LifecycleException { |
| fireLifecycleEvent(CONFIGURE_START_EVENT, null); |
| setState(LifecycleState.STARTING); |
| } |
| |
| |
| @Override |
| protected void stopInternal() throws LifecycleException { |
| cleanUp(); |
| setState(LifecycleState.STOPPING); |
| fireLifecycleEvent(CONFIGURE_STOP_EVENT, null); |
| } |
| |
| /** |
| * Close those resources that an explicit close may help clean-up faster. |
| */ |
| private void cleanUp() { |
| if (resources.size() == 0) { |
| return; |
| } |
| javax.naming.Context ctxt; |
| try { |
| if (container instanceof Server) { |
| ctxt = ((Server) container).getGlobalNamingContext(); |
| } else { |
| ctxt = ContextBindings.getClassLoader(); |
| ctxt = (javax.naming.Context) ctxt.lookup("comp/env"); |
| } |
| } catch (NamingException e) { |
| log.warn(sm.getString("namingResources.cleanupNoContext", |
| container), e); |
| return; |
| } |
| for (ContextResource cr: resources.values()) { |
| if (cr.getSingleton()) { |
| String closeMethod = cr.getCloseMethod(); |
| if (closeMethod != null && closeMethod.length() > 0) { |
| String name = cr.getName(); |
| Object resource; |
| try { |
| resource = ctxt.lookup(name); |
| } catch (NamingException e) { |
| log.warn(sm.getString( |
| "namingResources.cleanupNoResource", |
| cr.getName(), container), e); |
| continue; |
| } |
| cleanUp(resource, name, closeMethod); |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| * Clean up a resource by calling the defined close method. For example, |
| * closing a database connection pool will close it's open connections. This |
| * will happen on GC but that leaves db connections open that may cause |
| * issues. |
| * |
| * @param resource The resource to close. |
| */ |
| private void cleanUp(Object resource, String name, String closeMethod) { |
| // Look for a zero-arg close() method |
| Method m = null; |
| try { |
| m = resource.getClass().getMethod(closeMethod, (Class<?>[]) null); |
| } catch (SecurityException e) { |
| log.debug(sm.getString("namingResources.cleanupCloseSecurity", |
| closeMethod, name, container)); |
| return; |
| } catch (NoSuchMethodException e) { |
| log.debug(sm.getString("namingResources.cleanupNoClose", |
| name, container, closeMethod)); |
| return; |
| } |
| try { |
| m.invoke(resource, (Object[]) null); |
| } catch (IllegalArgumentException | IllegalAccessException e) { |
| log.warn(sm.getString("namingResources.cleanupCloseFailed", |
| closeMethod, name, container), e); |
| } catch (InvocationTargetException e) { |
| Throwable t = ExceptionUtils.unwrapInvocationTargetException(e); |
| ExceptionUtils.handleThrowable(t); |
| log.warn(sm.getString("namingResources.cleanupCloseFailed", |
| closeMethod, name, container), t); |
| } |
| } |
| |
| @Override |
| protected void destroyInternal() throws LifecycleException { |
| |
| // Set this before we de-register currently known naming resources to |
| // avoid timing issues. Duplication de-registration is not an issue. |
| resourceRequireExplicitRegistration = false; |
| |
| // Destroy in reverse order to create, although it should not matter |
| for (ContextResourceLink crl : resourceLinks.values()) { |
| try { |
| MBeanUtils.destroyMBean(crl); |
| } catch (Exception e) { |
| log.warn(sm.getString( |
| "namingResources.mbeanDestroyFail", crl.getName()), e); |
| } |
| } |
| |
| for (ContextEnvironment ce : envs.values()) { |
| try { |
| MBeanUtils.destroyMBean(ce); |
| } catch (Exception e) { |
| log.warn(sm.getString( |
| "namingResources.mbeanDestroyFail", ce.getName()), e); |
| } |
| } |
| |
| for (ContextResource cr : resources.values()) { |
| try { |
| MBeanUtils.destroyMBean(cr); |
| } catch (Exception e) { |
| log.warn(sm.getString( |
| "namingResources.mbeanDestroyFail", cr.getName()), e); |
| } |
| } |
| |
| super.destroyInternal(); |
| } |
| |
| |
| @Override |
| protected String getDomainInternal() { |
| // Use the same domain as our associated container if we have one |
| Object c = getContainer(); |
| |
| if (c instanceof JmxEnabled) { |
| return ((JmxEnabled) c).getDomain(); |
| } |
| |
| return null; |
| } |
| |
| |
| @Override |
| protected String getObjectNameKeyProperties() { |
| Object c = getContainer(); |
| if (c instanceof Container) { |
| return "type=NamingResources" + |
| ((Container) c).getMBeanKeyProperties(); |
| } |
| // Server or just unknown |
| return "type=NamingResources"; |
| } |
| |
| /** |
| * Checks that the configuration of the type for the specified resource is |
| * consistent with any injection targets and if the type is not specified, |
| * tries to configure the type based on the injection targets |
| * |
| * @param resource The resource to check |
| * |
| * @return <code>true</code> if the type for the resource is now valid (if |
| * previously <code>null</code> this means it is now set) or |
| * <code>false</code> if the current resource type is inconsistent |
| * with the injection targets and/or cannot be determined |
| */ |
| private boolean checkResourceType(ResourceBase resource) { |
| if (!(container instanceof Context)) { |
| // Only Context's will have injection targets |
| return true; |
| } |
| |
| if (resource.getInjectionTargets() == null || |
| resource.getInjectionTargets().size() == 0) { |
| // No injection targets so use the defined type for the resource |
| return true; |
| } |
| |
| Context context = (Context) container; |
| |
| String typeName = resource.getType(); |
| Class<?> typeClass = null; |
| if (typeName != null) { |
| typeClass = Introspection.loadClass(context, typeName); |
| if (typeClass == null) { |
| // Can't load the type - will trigger a failure later so don't |
| // fail here |
| return true; |
| } |
| } |
| |
| Class<?> compatibleClass = |
| getCompatibleType(context, resource, typeClass); |
| if (compatibleClass == null) { |
| // Indicates that a compatible type could not be identified that |
| // worked for all injection targets |
| return false; |
| } |
| |
| resource.setType(compatibleClass.getCanonicalName()); |
| return true; |
| } |
| |
| private Class<?> getCompatibleType(Context context, |
| ResourceBase resource, Class<?> typeClass) { |
| |
| Class<?> result = null; |
| |
| for (InjectionTarget injectionTarget : resource.getInjectionTargets()) { |
| Class<?> clazz = Introspection.loadClass( |
| context, injectionTarget.getTargetClass()); |
| if (clazz == null) { |
| // Can't load class - therefore ignore this target |
| continue; |
| } |
| |
| // Look for a match |
| String targetName = injectionTarget.getTargetName(); |
| // Look for a setter match first |
| Class<?> targetType = getSetterType(clazz, targetName); |
| if (targetType == null) { |
| // Try a field match if no setter match |
| targetType = getFieldType(clazz,targetName); |
| } |
| if (targetType == null) { |
| // No match - ignore this injection target |
| continue; |
| } |
| targetType = Introspection.convertPrimitiveType(targetType); |
| |
| if (typeClass == null) { |
| // Need to find a common type amongst the injection targets |
| if (result == null) { |
| result = targetType; |
| } else if (targetType.isAssignableFrom(result)) { |
| // NO-OP - This will work |
| } else if (result.isAssignableFrom(targetType)) { |
| // Need to use more specific type |
| result = targetType; |
| } else { |
| // Incompatible types |
| return null; |
| } |
| } else { |
| // Each injection target needs to be consistent with the defined |
| // type |
| if (targetType.isAssignableFrom(typeClass)) { |
| result = typeClass; |
| } else { |
| // Incompatible types |
| return null; |
| } |
| } |
| } |
| return result; |
| } |
| |
| private Class<?> getSetterType(Class<?> clazz, String name) { |
| Method[] methods = Introspection.getDeclaredMethods(clazz); |
| if (methods != null && methods.length > 0) { |
| for (Method method : methods) { |
| if (Introspection.isValidSetter(method) && |
| Introspection.getPropertyName(method).equals(name)) { |
| return method.getParameterTypes()[0]; |
| } |
| } |
| } |
| return null; |
| } |
| |
| private Class<?> getFieldType(Class<?> clazz, String name) { |
| Field[] fields = Introspection.getDeclaredFields(clazz); |
| if (fields != null && fields.length > 0) { |
| for (Field field : fields) { |
| if (field.getName().equals(name)) { |
| return field.getType(); |
| } |
| } |
| } |
| return null; |
| } |
| } |