View Javadoc

1   /*
2    * Copyright 2007-2008 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.test;
17  
18  import java.lang.reflect.Method;
19  import java.util.ArrayList;
20  import java.util.Arrays;
21  import java.util.HashSet;
22  import java.util.List;
23  import java.util.Set;
24  
25  import org.apache.commons.lang.StringUtils;
26  import org.kuali.rice.core.api.config.property.ConfigContext;
27  import org.kuali.rice.core.api.lifecycle.Lifecycle;
28  import org.kuali.rice.test.lifecycles.JettyServerLifecycle;
29  import org.kuali.rice.test.server.JettyServer;
30  import org.kuali.rice.test.server.JettyServers;
31  
32  /**
33   * A test case that supports declaratively defining a JettServer to run via annotations.
34   * Although this class supports running JettyServers on a per-suite and per-test basis, there is a
35   * pragmatic issue of concurrently running webapp contexts in the same classloader, so the webapp
36   * will have to support this (e.g. not rely on static singletons...)
37   * Another issue is that there is no suite "shutdown" per se, so a Jetty started up in a suite
38   * lifecycle will never get explicitly shut down.
39   * @author Kuali Rice Team (rice.collab@kuali.org)
40   */
41  public abstract class JettyServerTestCase extends BaselineTestCase {
42      private static Set<String> classesHandled = new HashSet<String>();
43      
44      /**
45       * @see {@link BaselineTestCase#BaselineTestCase(String, Mode)
46       */
47      public JettyServerTestCase(String moduleName, Mode mode) {
48          super(moduleName, mode);
49      }
50  
51      /**
52       * @see {@link BaselineTestCase#BaselineTestCase(String)
53       */
54      public JettyServerTestCase(String moduleName) {
55          super(moduleName);
56      }
57  
58      private List<JettyServer> readPerTestDefinitions(Method method) {
59          return getJettyServerDefinitions((JettyServers) method.getAnnotation(JettyServers.class), (JettyServer) method.getAnnotation(JettyServer.class));
60      }
61  
62      private List<JettyServer> readSuiteServerDefinitions(Class clazz) {
63          return getJettyServerDefinitions((JettyServers) clazz.getAnnotation(JettyServers.class), (JettyServer) clazz.getAnnotation(JettyServer.class));
64      }
65  
66      private List<JettyServer> getJettyServerDefinitions(JettyServers servers, JettyServer server) {
67          List<JettyServer> defs = new ArrayList<JettyServer>();
68          if (servers != null) {
69              if (servers.servers() != null) {
70                  defs.addAll(Arrays.asList(servers.servers()));
71              }
72          }
73          if (server != null) {
74              defs.add(server);
75          }
76          return defs;
77      }
78  
79      protected JettyServerLifecycle constructJettyServerLifecycle(JettyServer def) {
80          String portConfigParam = def.portConfigParam();
81          if (StringUtils.isBlank(portConfigParam)) {
82              portConfigParam = null;
83          }
84          if (def.port() != JettyServer.CONFIG_PARAM_PORT && portConfigParam != null) {
85              throw new IllegalArgumentException("Either but not both of port or portConfigParam must be specified on JettyServer annotation");
86          }
87          if (def.port() == JettyServer.CONFIG_PARAM_PORT && portConfigParam == null) {
88              portConfigParam = "unittest.jetty." + def.context() + ".port";
89          }
90          JettyServerLifecycle lc;
91          if (def.port() != JettyServer.CONFIG_PARAM_PORT) {
92              lc = new RuntimePortJettyServerLifecycle(def.port(), "/" + def.context(), def.webapp());
93          } else {
94              lc = new RuntimePortJettyServerLifecycle(def.portConfigParam(), "/" + def.context(), def.webapp());
95          }
96          lc.setConfigMode(def.configMode());
97          lc.setAddWebappResourceLoaders(def.addWebappResourceLoader());
98          return lc;
99      }
100 
101     @Override
102     protected List<Lifecycle> getSuiteLifecycles() {
103         List<Lifecycle> lifecycles = super.getSuiteLifecycles();
104         List<Class> classesToHandle;
105         try {
106             classesToHandle = TestUtilities.getHierarchyClassesToHandle(this.getClass(), new Class[] { JettyServers.class, JettyServer.class }, classesHandled);
107         } catch (Exception e) {
108             throw new RuntimeException("Error determining classes to handle", e);
109         }
110         List<JettyServer> suiteDefs = new ArrayList<JettyServer>();
111         for (Class c: classesToHandle) {
112             suiteDefs.addAll(readSuiteServerDefinitions(c));
113             classesHandled.add(c.getName());
114         }
115         // add all our jetties...
116         for (JettyServer def: suiteDefs) {
117             lifecycles.add(constructJettyServerLifecycle(def));
118         }
119         return lifecycles;
120     }
121 
122     @Override
123     protected List<Lifecycle> getPerTestLifecycles() {
124         List<Lifecycle> lifecycles = super.getPerTestLifecycles();
125         List<JettyServer> defs = readPerTestDefinitions(method);
126         // add all our jetties...
127         for (JettyServer def: defs) {
128             lifecycles.add(constructJettyServerLifecycle(def));
129         }
130         return lifecycles;
131     }
132     
133     private static final class RuntimePortJettyServerLifecycle extends JettyServerLifecycle {
134         private String portConfigParam;
135         public RuntimePortJettyServerLifecycle(int port, String contextName, String relativeWebappRoot) {
136             super(port, contextName, relativeWebappRoot);
137         }
138         public RuntimePortJettyServerLifecycle(String portConfigParam, String contextName, String relativeWebappRoot) {
139             super(JettyServer.CONFIG_PARAM_PORT, contextName, relativeWebappRoot);
140             this.portConfigParam = portConfigParam;
141         }
142         public void start() throws Exception {
143             if (jettyServer.getPort() == JettyServer.CONFIG_PARAM_PORT) {
144                 String val = ConfigContext.getCurrentContextConfig().getProperty(portConfigParam);
145                 if (val == null) {
146                     throw new RuntimeException("Jetty port not found in config param: " + portConfigParam);
147                 }
148                 jettyServer.setPort(Integer.parseInt(val));
149             }
150             super.start();
151         }
152         @Override
153         public void stop() throws Exception {
154             System.err.println("Shutting down jetty");
155             super.stop();
156         }
157     }
158 }