| // |
| // ======================================================================== |
| // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.plus.webapp; |
| |
| import java.util.Iterator; |
| |
| import javax.naming.Context; |
| import javax.naming.InitialContext; |
| import javax.naming.NameNotFoundException; |
| |
| import org.eclipse.jetty.jndi.NamingUtil; |
| import org.eclipse.jetty.plus.annotation.Injection; |
| import org.eclipse.jetty.plus.annotation.InjectionCollection; |
| import org.eclipse.jetty.plus.annotation.LifeCycleCallback; |
| import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection; |
| import org.eclipse.jetty.plus.annotation.PostConstructCallback; |
| import org.eclipse.jetty.plus.annotation.PreDestroyCallback; |
| import org.eclipse.jetty.plus.annotation.RunAsCollection; |
| import org.eclipse.jetty.plus.jndi.EnvEntry; |
| import org.eclipse.jetty.plus.jndi.Link; |
| import org.eclipse.jetty.plus.jndi.NamingEntry; |
| import org.eclipse.jetty.plus.jndi.NamingEntryUtil; |
| import org.eclipse.jetty.util.TypeUtil; |
| import org.eclipse.jetty.util.log.Log; |
| import org.eclipse.jetty.util.log.Logger; |
| import org.eclipse.jetty.webapp.Descriptor; |
| import org.eclipse.jetty.webapp.FragmentDescriptor; |
| import org.eclipse.jetty.webapp.IterativeDescriptorProcessor; |
| import org.eclipse.jetty.webapp.Origin; |
| import org.eclipse.jetty.webapp.WebAppContext; |
| import org.eclipse.jetty.xml.XmlParser; |
| |
| /** |
| * PlusDescriptorProcessor |
| */ |
| public class PlusDescriptorProcessor extends IterativeDescriptorProcessor |
| { |
| private static final Logger LOG = Log.getLogger(PlusDescriptorProcessor.class); |
| |
| public PlusDescriptorProcessor () |
| { |
| try |
| { |
| registerVisitor("env-entry", getClass().getMethod("visitEnvEntry", __signature)); |
| registerVisitor("resource-ref", getClass().getMethod("visitResourceRef", __signature)); |
| registerVisitor("resource-env-ref", getClass().getMethod("visitResourceEnvRef", __signature)); |
| registerVisitor("message-destination-ref", getClass().getMethod("visitMessageDestinationRef", __signature)); |
| registerVisitor("post-construct", getClass().getMethod("visitPostConstruct", __signature)); |
| registerVisitor("pre-destroy", getClass().getMethod("visitPreDestroy", __signature)); |
| } |
| catch (Exception e) |
| { |
| throw new IllegalStateException(e); |
| } |
| } |
| |
| /** |
| * @see org.eclipse.jetty.webapp.IterativeDescriptorProcessor#start(WebAppContext, org.eclipse.jetty.webapp.Descriptor) |
| */ |
| public void start(WebAppContext context, Descriptor descriptor) |
| { |
| |
| InjectionCollection injections = (InjectionCollection)context.getAttribute(InjectionCollection.INJECTION_COLLECTION); |
| if (injections == null) |
| { |
| injections = new InjectionCollection(); |
| context.setAttribute(InjectionCollection.INJECTION_COLLECTION, injections); |
| } |
| |
| LifeCycleCallbackCollection callbacks = (LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION); |
| if (callbacks == null) |
| { |
| callbacks = new LifeCycleCallbackCollection(); |
| context.setAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION, callbacks); |
| } |
| |
| RunAsCollection runAsCollection = (RunAsCollection)context.getAttribute(RunAsCollection.RUNAS_COLLECTION); |
| if (runAsCollection == null) |
| { |
| runAsCollection = new RunAsCollection(); |
| context.setAttribute(RunAsCollection.RUNAS_COLLECTION, runAsCollection); |
| } |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void end(WebAppContext context,Descriptor descriptor) |
| { |
| } |
| |
| /** |
| * JavaEE 5.4.1.3 |
| * |
| * @param context the context |
| * @param descriptor the descriptor |
| * @param node the xml node |
| * @throws Exception if unable to process jndi bindings |
| */ |
| public void visitEnvEntry (WebAppContext context, Descriptor descriptor, XmlParser.Node node) |
| throws Exception |
| { |
| String name=node.getString("env-entry-name",false,true); |
| String type = node.getString("env-entry-type",false,true); |
| String valueStr = node.getString("env-entry-value",false,true); |
| |
| //if there's no value there's no point in making a jndi entry |
| //nor processing injection entries |
| if (valueStr==null || valueStr.equals("")) |
| { |
| LOG.warn("No value for env-entry-name "+name); |
| return; |
| } |
| |
| Origin o = context.getMetaData().getOrigin("env-entry."+name); |
| switch (o) |
| { |
| case NotSet: |
| { |
| //no descriptor has configured an env-entry of this name previously |
| context.getMetaData().setOrigin("env-entry."+name, descriptor); |
| //the javaee_5.xsd says that the env-entry-type is optional |
| //if there is an <injection> element, because you can get |
| //type from the element, but what to do if there is more |
| //than one <injection> element, do you just pick the type |
| //of the first one? |
| addInjections (context, descriptor, node, name, TypeUtil.fromName(type)); |
| Object value = TypeUtil.valueOf(type,valueStr); |
| bindEnvEntry(name, value); |
| break; |
| } |
| case WebXml: |
| case WebDefaults: |
| case WebOverride: |
| { |
| //ServletSpec 3.0 p75. web.xml (or web-override/web-defaults) declared |
| //the env-entry. A fragment is not allowed to change that, except unless |
| //the web.xml did not declare any injections. |
| if (!(descriptor instanceof FragmentDescriptor)) |
| { |
| //We're processing web-defaults, web.xml or web-override. Any of them can |
| //set or change the env-entry. |
| context.getMetaData().setOrigin("env-entry."+name, descriptor); |
| addInjections (context, descriptor, node, name, TypeUtil.fromName(type)); |
| Object value = TypeUtil.valueOf(type,valueStr); |
| bindEnvEntry(name, value); |
| } |
| else |
| { |
| //A web.xml declared the env-entry. Check to see if any injections have been |
| //declared for it. If it was declared in web.xml then don't merge any injections. |
| //If it was declared in a web-fragment, then we can keep merging fragments. |
| Descriptor d = context.getMetaData().getOriginDescriptor("env-entry."+name+".injection"); |
| if (d==null || d instanceof FragmentDescriptor) |
| addInjections(context, descriptor, node, name, TypeUtil.fromName(type)); |
| } |
| break; |
| } |
| case WebFragment: |
| { |
| //ServletSpec p.75. No declaration in web.xml, but in multiple web-fragments. Error. |
| throw new IllegalStateException("Conflicting env-entry "+name+" in "+descriptor.getResource()); |
| } |
| } |
| } |
| |
| |
| /** |
| * Common Annotations Spec section 2.3: |
| * <p> |
| * resource-ref is for: |
| * <ul> |
| * <li>javax.sql.DataSource</li> |
| * <li>javax.jms.ConnectionFactory</li> |
| * <li>javax.jms.QueueConnectionFactory</li> |
| * <li>javax.jms.TopicConnectionFactory</li> |
| * <li>javax.mail.Session</li> |
| * <li>java.net.URL</li> |
| * <li>javax.resource.cci.ConnectionFactory</li> |
| * <li>org.omg.CORBA_2_3.ORB</li> |
| * <li>any other connection factory defined by a resource adapter</li> |
| * </ul> |
| * |
| * If web.xml contains a resource-ref with injection targets, all resource-ref entries |
| * of the same name are ignored in web fragments. If web.xml does not contain any |
| * injection-targets, then they are merged from all the fragments. |
| * If web.xml does not contain a resource-ref element of same name, but 2 fragments |
| * declare the same name it is an error. |
| * resource-ref entries are ONLY for connection factories |
| * the resource-ref says how the app will reference the jndi lookup relative |
| * to java:comp/env, but it is up to the deployer to map this reference to |
| * a real resource in the environment. At the moment, we insist that the |
| * jetty.xml file name of the resource has to be exactly the same as the |
| * name in web.xml deployment descriptor, but it shouldn't have to be |
| * |
| * <p> |
| * Maintenance update 3.0a to spec: |
| * <p> |
| * Update Section 8.2.3.h.ii with the following - If a resource reference |
| * element is specified in two fragments, while absent from the main web.xml, |
| * and all the attributes and child elements of the resource reference element |
| * are identical, the resource reference will be merged into the main web.xml. |
| * It is considered an error if a resource reference element has the same name |
| * specified in two fragments, while absent from the main web.xml and the attributes |
| * and child elements are not identical in the two fragments. For example, if two |
| * web fragments declare a <code><resource-ref></code> with the same <code><resource-ref-name></code> element |
| * but the type in one is specified as javax.sql.DataSource while the type in the |
| * other is that of a java mail resource, then an error must be reported and the |
| * application MUST fail to deploy. |
| * |
| * @param context the context |
| * @param descriptor the descriptor |
| * @param node the xml node |
| * @throws Exception if unable to bind nodes, or load classes |
| */ |
| public void visitResourceRef (WebAppContext context, Descriptor descriptor, XmlParser.Node node) |
| throws Exception |
| { |
| String jndiName = node.getString("res-ref-name",false,true); |
| String type = node.getString("res-type", false, true); |
| String auth = node.getString("res-auth", false, true); |
| String shared = node.getString("res-sharing-scope", false, true); |
| |
| Origin o = context.getMetaData().getOrigin("resource-ref."+jndiName); |
| switch (o) |
| { |
| case NotSet: |
| { |
| //No descriptor or annotation previously declared a resource-ref of this name. |
| context.getMetaData().setOrigin("resource-ref."+jndiName, descriptor); |
| |
| //check for <injection> elements |
| Class<?> typeClass = TypeUtil.fromName(type); |
| if (typeClass==null) |
| typeClass = context.loadClass(type); |
| addInjections(context, descriptor, node, jndiName, typeClass); |
| bindResourceRef(context,jndiName, typeClass); |
| break; |
| } |
| case WebXml: |
| case WebDefaults: |
| case WebOverride: |
| { |
| //A web xml previously declared the resource-ref. |
| if (!(descriptor instanceof FragmentDescriptor)) |
| { |
| //We're processing web-defaults, web.xml or web-override. Any of them can |
| //set or change the resource-ref. |
| context.getMetaData().setOrigin("resource-ref."+jndiName, descriptor); |
| |
| //check for <injection> elements |
| Class<?> typeClass = TypeUtil.fromName(type); |
| if (typeClass==null) |
| typeClass = context.loadClass(type); |
| |
| addInjections(context, descriptor, node, jndiName, typeClass); |
| |
| //bind the entry into jndi |
| bindResourceRef(context,jndiName, typeClass); |
| } |
| else |
| { |
| //A web xml declared the resource-ref and we're processing a |
| //web-fragment. Check to see if any injections were declared for it by web.xml. |
| //If any injection was declared in web.xml then don't merge any injections. |
| //If it was declared in a web-fragment, then we can keep merging fragments. |
| Descriptor d = context.getMetaData().getOriginDescriptor("resource-ref."+jndiName+".injection"); |
| if (d==null || d instanceof FragmentDescriptor) |
| { |
| Class<?> typeClass = TypeUtil.fromName(type); |
| if (typeClass==null) |
| typeClass = context.loadClass(type); |
| addInjections(context, descriptor, node, jndiName, TypeUtil.fromName(type)); |
| } |
| } |
| break; |
| } |
| case WebFragment: |
| { |
| Descriptor otherFragment = context.getMetaData().getOriginDescriptor("resource-ref."+jndiName); |
| XmlParser.Node otherFragmentRoot = otherFragment.getRoot(); |
| Iterator<Object> iter = otherFragmentRoot.iterator(); |
| XmlParser.Node otherNode = null; |
| while (iter.hasNext() && otherNode == null) |
| { |
| Object obj = iter.next(); |
| if (!(obj instanceof XmlParser.Node)) continue; |
| XmlParser.Node n = (XmlParser.Node)obj; |
| if ("resource-ref".equals(n.getTag()) && jndiName.equals(n.getString("res-ref-name",false,true))) |
| otherNode = n; |
| } |
| |
| //If declared in another web-fragment |
| if (otherNode != null) |
| { |
| //declarations of the resource-ref must be the same in both fragment descriptors |
| String otherType = otherNode.getString("res-type", false, true); |
| String otherAuth = otherNode.getString("res-auth", false, true); |
| String otherShared = otherNode.getString("res-sharing-scope", false, true); |
| |
| //otherType, otherAuth and otherShared must be the same as type, auth, shared |
| type = (type == null?"":type); |
| otherType = (otherType == null?"":otherType); |
| auth = (auth == null?"":auth); |
| otherAuth = (otherAuth == null?"":otherAuth); |
| shared = (shared == null?"":shared); |
| otherShared = (otherShared == null?"":otherShared); |
| |
| //ServletSpec p.75. No declaration of resource-ref in web xml, but different in multiple web-fragments. Error. |
| if (!type.equals(otherType) || !auth.equals(otherAuth) || !shared.equals(otherShared)) |
| throw new IllegalStateException("Conflicting resource-ref "+jndiName+" in "+descriptor.getResource()); |
| //same in multiple web-fragments, merge the injections |
| addInjections(context, descriptor, node, jndiName, TypeUtil.fromName(type)); |
| } |
| else |
| throw new IllegalStateException("resource-ref."+jndiName+" not found in declaring descriptor "+otherFragment); |
| |
| } |
| } |
| |
| } |
| |
| |
| /** |
| * Common Annotations Spec section 2.3: |
| * <p> |
| * resource-env-ref is for: |
| * <ul> |
| * <li>javax.transaction.UserTransaction</li> |
| * <li>javax.resource.cci.InteractionSpec</li> |
| * <li>anything else that is not a connection factory</li> |
| * </ul> |
| * |
| * @param context the context |
| * @param descriptor the descriptor |
| * @param node the xml node |
| * @throws Exception if unable to load classes, or bind jndi entries |
| */ |
| public void visitResourceEnvRef (WebAppContext context, Descriptor descriptor, XmlParser.Node node) |
| throws Exception |
| { |
| String jndiName = node.getString("resource-env-ref-name",false,true); |
| String type = node.getString("resource-env-ref-type", false, true); |
| |
| Origin o = context.getMetaData().getOrigin("resource-env-ref."+jndiName); |
| switch (o) |
| { |
| case NotSet: |
| { |
| //First declaration of resource-env-ref with this jndiName |
| //JavaEE Spec sec 5.7.1.3 says the resource-env-ref-type |
| //is mandatory, but the schema says it is optional! |
| Class<?> typeClass = TypeUtil.fromName(type); |
| if (typeClass==null) |
| typeClass = context.loadClass(type); |
| addInjections (context, descriptor, node, jndiName, typeClass); |
| bindResourceEnvRef(context,jndiName, typeClass); |
| break; |
| } |
| case WebXml: |
| case WebDefaults: |
| case WebOverride: |
| { |
| //A resource-env-ref of this name has been declared first in a web xml. |
| //Only allow other web-default, web.xml, web-override to change it. |
| if (!(descriptor instanceof FragmentDescriptor)) |
| { |
| //We're processing web-defaults, web.xml or web-override. Any of them can |
| //set or change the resource-env-ref. |
| context.getMetaData().setOrigin("resource-env-ref."+jndiName, descriptor); |
| Class<?> typeClass = TypeUtil.fromName(type); |
| if (typeClass==null) |
| typeClass = context.loadClass(type); |
| addInjections (context, descriptor, node, jndiName, typeClass); |
| bindResourceEnvRef(context,jndiName, typeClass); |
| } |
| else |
| { |
| //We're processing a web-fragment. It can only contribute injections if the |
| //there haven't been any injections declared yet, or they weren't declared in a WebXml file. |
| Descriptor d = context.getMetaData().getOriginDescriptor("resource-env-ref."+jndiName+".injection"); |
| if (d == null || d instanceof FragmentDescriptor) |
| { |
| Class<?> typeClass = TypeUtil.fromName(type); |
| if (typeClass==null) |
| typeClass = context.loadClass(type); |
| addInjections (context, descriptor, node, jndiName, typeClass); |
| } |
| } |
| break; |
| } |
| case WebFragment: |
| { |
| Descriptor otherFragment = context.getMetaData().getOriginDescriptor("resource-env-ref."+jndiName); |
| XmlParser.Node otherFragmentRoot = otherFragment.getRoot(); |
| Iterator<Object> iter = otherFragmentRoot.iterator(); |
| XmlParser.Node otherNode = null; |
| while (iter.hasNext() && otherNode == null) |
| { |
| Object obj = iter.next(); |
| if (!(obj instanceof XmlParser.Node)) continue; |
| XmlParser.Node n = (XmlParser.Node)obj; |
| if ("resource-env-ref".equals(n.getTag()) && jndiName.equals(n.getString("resource-env-ref-name",false,true))) |
| otherNode = n; |
| } |
| if (otherNode != null) |
| { |
| //declarations of the resource-ref must be the same in both fragment descriptors |
| String otherType = otherNode.getString("resource-env-ref-type", false, true); |
| |
| //types must be the same |
| type = (type == null?"":type); |
| otherType = (otherType == null?"":otherType); |
| |
| //ServletSpec p.75. No declaration of resource-ref in web xml, but different in multiple web-fragments. Error. |
| if (!type.equals(otherType)) |
| throw new IllegalStateException("Conflicting resource-env-ref "+jndiName+" in "+descriptor.getResource()); |
| |
| //same in multiple web-fragments, merge the injections |
| addInjections(context, descriptor, node, jndiName, TypeUtil.fromName(type)); |
| } |
| else |
| throw new IllegalStateException("resource-env-ref."+jndiName+" not found in declaring descriptor "+otherFragment); |
| } |
| } |
| } |
| |
| |
| /** |
| * Common Annotations Spec section 2.3: |
| * <p> |
| * message-destination-ref is for: |
| * <ul> |
| * <li>javax.jms.Queue</li> |
| * <li>javax.jms.Topic</li> |
| * </ul> |
| * |
| * @param context the context |
| * @param descriptor the descriptor |
| * @param node the xml node |
| * @throws Exception if unable to load classes or bind jndi entries |
| */ |
| public void visitMessageDestinationRef (WebAppContext context, Descriptor descriptor, XmlParser.Node node) |
| throws Exception |
| { |
| String jndiName = node.getString("message-destination-ref-name",false,true); |
| String type = node.getString("message-destination-type",false,true); |
| String usage = node.getString("message-destination-usage",false,true); |
| |
| Origin o = context.getMetaData().getOrigin("message-destination-ref."+jndiName); |
| switch (o) |
| { |
| case NotSet: |
| { |
| //A message-destination-ref of this name has not been previously declared |
| Class<?> typeClass = TypeUtil.fromName(type); |
| if (typeClass==null) |
| typeClass = context.loadClass(type); |
| addInjections(context, descriptor, node, jndiName, typeClass); |
| bindMessageDestinationRef(context,jndiName, typeClass); |
| context.getMetaData().setOrigin("message-destination-ref."+jndiName, descriptor); |
| break; |
| } |
| case WebXml: |
| case WebDefaults: |
| case WebOverride: |
| { |
| //A message-destination-ref of this name has been declared first in a web xml. |
| //Only allow other web-default, web.xml, web-override to change it. |
| if (!(descriptor instanceof FragmentDescriptor)) |
| { |
| Class<?> typeClass = TypeUtil.fromName(type); |
| if (typeClass==null) |
| typeClass = context.loadClass(type); |
| addInjections(context, descriptor, node, jndiName, typeClass); |
| bindMessageDestinationRef(context,jndiName, typeClass); |
| context.getMetaData().setOrigin("message-destination-ref."+jndiName, descriptor); |
| } |
| else |
| { |
| //A web-fragment has declared a message-destination-ref with the same name as a web xml. |
| //It can only contribute injections, and only if the web xml didn't declare any. |
| Descriptor d = context.getMetaData().getOriginDescriptor("message-destination-ref."+jndiName+".injection"); |
| if (d == null || d instanceof FragmentDescriptor) |
| { |
| Class<?> typeClass = TypeUtil.fromName(type); |
| if (typeClass==null) |
| typeClass = context.loadClass(type); |
| addInjections(context, descriptor, node, jndiName, typeClass); |
| } |
| } |
| break; |
| } |
| case WebFragment: |
| { |
| Descriptor otherFragment = context.getMetaData().getOriginDescriptor("message-destination-ref."+jndiName); |
| XmlParser.Node otherFragmentRoot = otherFragment.getRoot(); |
| Iterator<Object> iter = otherFragmentRoot.iterator(); |
| XmlParser.Node otherNode = null; |
| while (iter.hasNext() && otherNode == null) |
| { |
| Object obj = iter.next(); |
| if (!(obj instanceof XmlParser.Node)) continue; |
| XmlParser.Node n = (XmlParser.Node)obj; |
| if ("message-destination-ref".equals(n.getTag()) && jndiName.equals(n.getString("message-destination-ref-name",false,true))) |
| otherNode = n; |
| } |
| if (otherNode != null) |
| { |
| String otherType = node.getString("message-destination-type",false,true); |
| String otherUsage = node.getString("message-destination-usage",false,true); |
| |
| type = (type==null?"":type); |
| usage = (usage==null?"":usage); |
| if (!type.equals(otherType) || !usage.equalsIgnoreCase(otherUsage)) |
| throw new IllegalStateException("Conflicting message-destination-ref "+jndiName+" in "+descriptor.getResource()); |
| |
| //same in multiple web-fragments, merge the injections |
| addInjections(context, descriptor, node, jndiName, TypeUtil.fromName(type)); |
| } |
| else |
| throw new IllegalStateException("message-destination-ref."+jndiName+" not found in declaring descriptor "+otherFragment); |
| } |
| } |
| |
| } |
| |
| |
| |
| /** |
| * If web.xml has at least 1 post-construct, then all post-constructs in fragments |
| * are ignored. Otherwise, post-constructs from fragments are merged. |
| * post-construct is the name of a class and method to call after all |
| * resources have been setup but before the class is put into use |
| * |
| * @param context the context |
| * @param descriptor the descriptor |
| * @param node the xml node |
| */ |
| public void visitPostConstruct(WebAppContext context, Descriptor descriptor, XmlParser.Node node) |
| { |
| String className = node.getString("lifecycle-callback-class", false, true); |
| String methodName = node.getString("lifecycle-callback-method", false, true); |
| |
| if (className==null || className.equals("")) |
| { |
| LOG.warn("No lifecycle-callback-class specified"); |
| return; |
| } |
| if (methodName==null || methodName.equals("")) |
| { |
| LOG.warn("No lifecycle-callback-method specified for class "+className); |
| return; |
| } |
| |
| //ServletSpec 3.0 p80 If web.xml declares a post-construct then all post-constructs |
| //in fragments must be ignored. Otherwise, they are additive. |
| Origin o = context.getMetaData().getOrigin("post-construct"); |
| switch (o) |
| { |
| case NotSet: |
| { |
| //No post-constructs have been declared previously. |
| context.getMetaData().setOrigin("post-construct", descriptor); |
| |
| try |
| { |
| Class<?> clazz = context.loadClass(className); |
| LifeCycleCallback callback = new PostConstructCallback(); |
| callback.setTarget(clazz, methodName); |
| ((LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION)).add(callback); |
| } |
| catch (ClassNotFoundException e) |
| { |
| LOG.warn("Couldn't load post-construct target class "+className); |
| } |
| break; |
| } |
| case WebXml: |
| case WebDefaults: |
| case WebOverride: |
| { |
| //A web xml first declared a post-construct. Only allow other web xml files (web-defaults, web-overrides etc) |
| //to add to it |
| if (!(descriptor instanceof FragmentDescriptor)) |
| { |
| try |
| { |
| Class<?> clazz = context.loadClass(className); |
| LifeCycleCallback callback = new PostConstructCallback(); |
| callback.setTarget(clazz, methodName); |
| ((LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION)).add(callback); |
| } |
| catch (ClassNotFoundException e) |
| { |
| LOG.warn("Couldn't load post-construct target class "+className); |
| } |
| } |
| break; |
| } |
| case WebFragment: |
| { |
| //A web-fragment first declared a post-construct. Allow all other web-fragments to merge in their post-constructs |
| try |
| { |
| Class<?> clazz = context.loadClass(className); |
| LifeCycleCallback callback = new PostConstructCallback(); |
| callback.setTarget(clazz, methodName); |
| ((LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION)).add(callback); |
| } |
| catch (ClassNotFoundException e) |
| { |
| LOG.warn("Couldn't load post-construct target class "+className); |
| } |
| break; |
| } |
| } |
| |
| } |
| |
| |
| /** |
| * |
| * pre-destroy is the name of a class and method to call just as |
| * the instance is being destroyed |
| * |
| * @param context the context |
| * @param descriptor the descriptor |
| * @param node the xml node |
| */ |
| public void visitPreDestroy(WebAppContext context, Descriptor descriptor, XmlParser.Node node) |
| { |
| String className = node.getString("lifecycle-callback-class", false, true); |
| String methodName = node.getString("lifecycle-callback-method", false, true); |
| if (className==null || className.equals("")) |
| { |
| LOG.warn("No lifecycle-callback-class specified for pre-destroy"); |
| return; |
| } |
| if (methodName==null || methodName.equals("")) |
| { |
| LOG.warn("No lifecycle-callback-method specified for pre-destroy class "+className); |
| return; |
| } |
| |
| Origin o = context.getMetaData().getOrigin("pre-destroy"); |
| switch(o) |
| { |
| case NotSet: |
| { |
| //No pre-destroys have been declared previously. Record this descriptor |
| //as the first declarer. |
| context.getMetaData().setOrigin("pre-destroy", descriptor); |
| try |
| { |
| Class<?> clazz = context.loadClass(className); |
| LifeCycleCallback callback = new PreDestroyCallback(); |
| callback.setTarget(clazz, methodName); |
| ((LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION)).add(callback); |
| } |
| catch (ClassNotFoundException e) |
| { |
| LOG.warn("Couldn't load pre-destory target class "+className); |
| } |
| break; |
| } |
| case WebXml: |
| case WebDefaults: |
| case WebOverride: |
| { |
| //A web xml file previously declared a pre-destroy. Only allow other web xml files |
| //(not web-fragments) to add to them. |
| if (!(descriptor instanceof FragmentDescriptor)) |
| { |
| try |
| { |
| Class<?> clazz = context.loadClass(className); |
| LifeCycleCallback callback = new PreDestroyCallback(); |
| callback.setTarget(clazz, methodName); |
| ((LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION)).add(callback); |
| } |
| catch (ClassNotFoundException e) |
| { |
| LOG.warn("Couldn't load pre-destory target class "+className); |
| } |
| } |
| break; |
| } |
| case WebFragment: |
| { |
| //No pre-destroys in web xml, so allow all fragments to merge their pre-destroys. |
| try |
| { |
| Class<?> clazz = context.loadClass(className); |
| LifeCycleCallback callback = new PreDestroyCallback(); |
| callback.setTarget(clazz, methodName); |
| ((LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION)).add(callback); |
| } |
| catch (ClassNotFoundException e) |
| { |
| LOG.warn("Couldn't load pre-destory target class "+className); |
| } |
| break; |
| } |
| } |
| } |
| |
| |
| /** |
| * Iterate over the <code><injection-target></code> entries for a node |
| * |
| * @param context the context |
| * @param descriptor the descriptor |
| * @param node the xml node |
| * @param jndiName the jndi name |
| * @param valueClass the value class |
| */ |
| public void addInjections (WebAppContext context, Descriptor descriptor, XmlParser.Node node, String jndiName, Class<?> valueClass) |
| { |
| Iterator<XmlParser.Node> itor = node.iterator("injection-target"); |
| |
| while(itor.hasNext()) |
| { |
| XmlParser.Node injectionNode = itor.next(); |
| String targetClassName = injectionNode.getString("injection-target-class", false, true); |
| String targetName = injectionNode.getString("injection-target-name", false, true); |
| if ((targetClassName==null) || targetClassName.equals("")) |
| { |
| LOG.warn("No classname found in injection-target"); |
| continue; |
| } |
| if ((targetName==null) || targetName.equals("")) |
| { |
| LOG.warn("No field or method name in injection-target"); |
| continue; |
| } |
| |
| InjectionCollection injections = (InjectionCollection)context.getAttribute(InjectionCollection.INJECTION_COLLECTION); |
| if (injections == null) |
| { |
| injections = new InjectionCollection(); |
| context.setAttribute(InjectionCollection.INJECTION_COLLECTION, injections); |
| } |
| // comments in the javaee_5.xsd file specify that the targetName is looked |
| // for first as a java bean property, then if that fails, as a field |
| try |
| { |
| Class<?> clazz = context.loadClass(targetClassName); |
| Injection injection = new Injection(); |
| injection.setJndiName(jndiName); |
| injection.setTarget(clazz, targetName, valueClass); |
| injections.add(injection); |
| |
| //Record which was the first descriptor to declare an injection for this name |
| if (context.getMetaData().getOriginDescriptor(node.getTag()+"."+jndiName+".injection") == null) |
| context.getMetaData().setOrigin(node.getTag()+"."+jndiName+".injection", descriptor); |
| } |
| catch (ClassNotFoundException e) |
| { |
| LOG.warn("Couldn't load injection target class "+targetClassName); |
| } |
| } |
| } |
| |
| |
| |
| |
| /** |
| * @param name the jndi name |
| * @param value the value |
| * @throws Exception if unable to bind entry |
| */ |
| public void bindEnvEntry(String name, Object value) throws Exception |
| { |
| InitialContext ic = null; |
| boolean bound = false; |
| //check to see if we bound a value and an EnvEntry with this name already |
| //when we processed the server and the webapp's naming environment |
| //@see EnvConfiguration.bindEnvEntries() |
| ic = new InitialContext(); |
| try |
| { |
| NamingEntry ne = (NamingEntry)ic.lookup("java:comp/env/"+NamingEntryUtil.makeNamingEntryName(ic.getNameParser(""), name)); |
| if (ne!=null && ne instanceof EnvEntry) |
| { |
| EnvEntry ee = (EnvEntry)ne; |
| bound = ee.isOverrideWebXml(); |
| } |
| } |
| catch (NameNotFoundException e) |
| { |
| bound = false; |
| } |
| |
| if (!bound) |
| { |
| //either nothing was bound or the value from web.xml should override |
| Context envCtx = (Context)ic.lookup("java:comp/env"); |
| NamingUtil.bind(envCtx, name, value); |
| } |
| } |
| |
| /** |
| * Bind a resource reference. |
| * <p> |
| * If a resource reference with the same name is in a jetty-env.xml |
| * file, it will already have been bound. |
| * |
| * @param context the context |
| * @param name the jndi name |
| * @param typeClass the type class |
| * @throws Exception if unable to bind resource |
| */ |
| public void bindResourceRef(WebAppContext context, String name, Class<?> typeClass) |
| throws Exception |
| { |
| bindEntry(context, name, typeClass); |
| } |
| |
| public void bindResourceEnvRef(WebAppContext context, String name, Class<?> typeClass) |
| throws Exception |
| { |
| bindEntry(context, name, typeClass); |
| } |
| |
| |
| public void bindMessageDestinationRef(WebAppContext context, String name, Class<?> typeClass) |
| throws Exception |
| { |
| bindEntry(context, name, typeClass); |
| } |
| |
| |
| /** |
| * Bind a resource with the given name from web.xml of the given type |
| * with a jndi resource from either the server or the webapp's naming |
| * environment. |
| * <p> |
| * As the servlet spec does not cover the mapping of names in web.xml with |
| * names from the execution environment, jetty uses the concept of a Link, which is |
| * a subclass of the NamingEntry class. A Link defines a mapping of a name |
| * from web.xml with a name from the execution environment (ie either the server or the |
| * webapp's naming environment). |
| * |
| * @param context the context |
| * @param name name of the resource from web.xml |
| * @param typeClass the type class |
| * @throws Exception the exception |
| */ |
| protected void bindEntry (WebAppContext context, String name, Class<?> typeClass) |
| throws Exception |
| { |
| String nameInEnvironment = name; |
| boolean bound = false; |
| |
| //check if the name in web.xml has been mapped to something else |
| //check a context-specific naming environment first |
| Object scope = context; |
| NamingEntry ne = NamingEntryUtil.lookupNamingEntry(scope, name); |
| |
| if (ne!=null && (ne instanceof Link)) |
| { |
| //if we found a mapping, get out name it is mapped to in the environment |
| nameInEnvironment = ((Link)ne).getLink(); |
| } |
| |
| //try finding that mapped name in the webapp's environment first |
| scope = context; |
| bound = NamingEntryUtil.bindToENC(scope, name, nameInEnvironment); |
| |
| if (bound) |
| return; |
| |
| //try the server's environment |
| scope = context.getServer(); |
| bound = NamingEntryUtil.bindToENC(scope, name, nameInEnvironment); |
| if (bound) |
| return; |
| |
| //try the jvm environment |
| bound = NamingEntryUtil.bindToENC(null, name, nameInEnvironment); |
| if (bound) |
| return; |
| |
| //There is no matching resource so try a default name. |
| //The default name syntax is: the [res-type]/default |
| //eg javax.sql.DataSource/default |
| nameInEnvironment = typeClass.getName()+"/default"; |
| //First try the server scope |
| NamingEntry defaultNE = NamingEntryUtil.lookupNamingEntry(context.getServer(), nameInEnvironment); |
| if (defaultNE==null) |
| defaultNE = NamingEntryUtil.lookupNamingEntry(null, nameInEnvironment); |
| |
| if (defaultNE!=null) |
| defaultNE.bindToENC(name); |
| else |
| throw new IllegalStateException("Nothing to bind for name " + name); |
| } |
| |
| |
| } |