001 /**
002 * Copyright 2010 The Kuali Foundation Licensed under the
003 * Educational Community License, Version 2.0 (the "License"); you may
004 * not use this file except in compliance with the License. You may
005 * obtain a copy of the License at
006 *
007 * http://www.osedu.org/licenses/ECL-2.0
008 *
009 * Unless required by applicable law or agreed to in writing,
010 * software distributed under the License is distributed on an "AS IS"
011 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
012 * or implied. See the License for the specific language governing
013 * permissions and limitations under the License.
014 */
015
016 package org.kuali.student.common.test.spring;
017
018 import java.lang.reflect.Field;
019 import java.util.EventListener;
020 import java.util.HashMap;
021 import java.util.Map;
022
023 import javax.jws.WebService;
024 import javax.servlet.Servlet;
025 import javax.xml.namespace.QName;
026
027 import org.junit.internal.runners.InitializationError;
028 import org.junit.internal.runners.JUnit4ClassRunner;
029 import org.junit.runner.notification.RunNotifier;
030 import org.kuali.student.common.ws.beans.JaxWsClientFactory;
031 import org.mortbay.jetty.Server;
032 import org.mortbay.jetty.servlet.Context;
033 import org.mortbay.jetty.servlet.ServletHandler;
034 import org.mortbay.jetty.servlet.ServletHolder;
035 import org.mortbay.jetty.servlet.ServletMapping;
036 import org.springframework.web.context.ContextLoaderListener;
037
038 public class ServiceTestClassRunner extends JUnit4ClassRunner {
039 private final Class<?> testImplClass;
040 private Server server;
041
042 public ServiceTestClassRunner(Class<?> klass) throws InitializationError {
043 super(klass);
044 testImplClass = klass;
045
046 }
047
048 /**
049 * Creates a client and injects it into the test class based on the
050 * @Client annotations
051 */
052 /*
053 * (non-Javadoc)
054 *
055 * @see org.junit.internal.runners.JUnit4ClassRunner#createTest()
056 */
057 @Override
058 protected Object createTest() throws Exception {
059 Object instance = super.createTest();
060 try {
061 for (Field f : instance.getClass().getDeclaredFields()) {
062 if (f.isAnnotationPresent(Client.class)) {
063 Client a = f.getAnnotation(Client.class);
064 String port = System.getProperty("ks.test.port");
065
066 Class<?> serviceImplClass = Class.forName(a.value());
067 String serviceName = "";
068 String serviceNamespaceURI = "";
069 String serviceWsdlLocation = "http://localhost:" + port
070 + "/Service/Service" + (a.secure() ? "Secure" : "")
071 + "?wsdl";
072 String serviceAddress = "http://localhost:" + port
073 + "/Service/Service" + (a.secure() ? "Secure" : "");
074
075 if (serviceImplClass.isAnnotationPresent(WebService.class)) {
076 WebService wsAnnotation = serviceImplClass
077 .getAnnotation(WebService.class);
078 serviceName = wsAnnotation.serviceName();
079 serviceNamespaceURI = wsAnnotation.targetNamespace();
080 }
081
082 Class<?> clientImplClass = Class
083 .forName("org.kuali.student.common.ws.beans.JaxWsClientFactoryBean");
084
085 if (a.secure()) {
086 try {
087 clientImplClass = Class
088 .forName("org.kuali.student.common.cxf.security.SecureJaxWsProxyFactoryBean");
089 } catch (ClassNotFoundException cnfe) {
090 }
091 }
092
093 JaxWsClientFactory clientFactory = (JaxWsClientFactory) clientImplClass
094 .newInstance();
095
096 clientFactory.setServiceEndpointInterface(f.getType());
097 clientFactory.setServiceName(new QName(serviceNamespaceURI,
098 serviceName));
099 clientFactory.setWsdlLocation(serviceWsdlLocation);
100 clientFactory.setAddress(serviceAddress);
101
102 f.setAccessible(true);
103 f.set(instance, clientFactory.getObject());
104 }
105 }
106 } catch (Exception e) {
107 throw new RuntimeException(e);
108 }
109 return instance;
110 }
111
112 /**
113 * Start a server based on the service Impl @WebService annotaions and
114 * the test class @
115 */
116 private void startServer() {
117 try {
118 // Set the default Port
119 if (System.getProperty("ks.test.default.port")==null||System.getProperty("ks.test.default.port").isEmpty()){
120 System.setProperty("ks.test.port", "9191");
121 } else {
122 System.setProperty("ks.test.port", System.getProperty("ks.test.default.port"));
123 }
124
125 // Grab the client annotation and set the service implementation and
126 // port as system properties
127 for (Field f : testImplClass.getDeclaredFields()) {
128 if (f.isAnnotationPresent(Client.class)) {
129 Client a = f.getAnnotation(Client.class);
130 if (a.secure()) {
131 System.setProperty("ks.test.serviceImplSecure", a
132 .value());
133 } else {
134 System.setProperty("ks.test.serviceImplClass", a
135 .value());
136 }
137 if(a.port()!=null&&!a.port().isEmpty()){
138 System.setProperty("ks.test.port", a.port());
139 }
140 if(!"".equals(a.additionalContextFile())){
141 System.setProperty("ks.test.additionalContextFile", a.additionalContextFile());
142 }else{
143 System.setProperty("ks.test.additionalContextFile", "classpath:*noSuchContextFile.xml");
144 }
145 }
146 }
147
148 // If no secure client defined, set secure service endpoint impl
149 // to be same as non-secure endpoint impl
150 if (System.getProperty("ks.test.serviceImplSecure") == null) {
151 System.setProperty("ks.test.serviceImplSecure", System
152 .getProperty("ks.test.serviceImplClass"));
153 }
154
155 // Grab the persistence context loacation or set a default value
156 if (testImplClass
157 .isAnnotationPresent(PersistenceFileLocation.class)) {
158 PersistenceFileLocation a = testImplClass
159 .getAnnotation(PersistenceFileLocation.class);
160 System.setProperty("ks.test.persistenceLocation", a.value());
161 } else {
162 System.setProperty("ks.test.persistenceLocation",
163 "classpath:META-INF/persistence.xml");
164 }
165
166 // Grab the Dao information and pass it to a System variable
167 Daos daos = testImplClass.getAnnotation(Daos.class);
168
169 String daoImpls = "";
170 if (daos != null) {
171 int i = 1;
172 for (Dao dao : daos.value()) {
173 daoImpls += dao.value() + "|" + dao.testDataFile() +"|" + dao.testSqlFile() ;
174 if (i < daos.value().length) {
175 daoImpls += ",";
176 }
177 i++;
178 }
179 }
180 System.setProperty("ks.test.daoImplClasses", daoImpls);
181
182 server = new Server(Integer.valueOf(System
183 .getProperty("ks.test.port")));
184
185 Context context = new Context();
186 ServletHandler servletHandler = new ServletHandler();
187 ServletHolder servletHolder = new ServletHolder();
188 ServletMapping servletMapping = new ServletMapping();
189 ContextLoaderListener contextLoaderListener = new ContextLoaderListener();
190
191
192 Class<?> servletClass;
193 String wsEngine;
194 try{
195 servletClass = Class.forName("org.apache.cxf.transport.servlet.CXFServlet");
196 wsEngine = "cxf";
197 } catch (ClassNotFoundException e) {
198 servletClass = Class.forName("com.sun.xml.ws.transport.http.servlet.WSSpringServlet");
199 wsEngine = "jaxws";
200 }
201
202 Servlet servlet = (Servlet) servletClass.newInstance();
203
204 servletHolder.setName("Service");
205 servletHolder.setServlet(servlet);
206 servletHandler.setServlets(new ServletHolder[] { servletHolder });
207
208 servletMapping.setPathSpec("/*");
209 servletMapping.setServletName("Service");
210 servletHandler
211 .setServletMappings(new ServletMapping[] { servletMapping });
212
213 context.setContextPath("/Service");
214 context.setResourceBase("src/test/resources");
215
216 Map<String, String> initParams = new HashMap<String, String>();
217
218 //Set the context config location
219 String contextConfigLocation = "classpath:META-INF/" + wsEngine + "-context.xml";
220 if(!"".equals(daoImpls)){
221 //If there are Daos defined, add the dao context file
222 contextConfigLocation +="\nclasspath:META-INF/default-dao-context-test.xml";
223 }
224
225 initParams.put("contextConfigLocation", contextConfigLocation);
226 initParams.put("log4jConfigLocation", "log4j.properties");
227 context.setInitParams(initParams);
228 context
229 .setEventListeners(new EventListener[] { contextLoaderListener });
230 context.setServletHandler(servletHandler);
231
232 server.setHandler(context);
233
234 server.start();
235 } catch (Exception e) {
236 throw new RuntimeException(e);
237 }
238
239 }
240
241 /*
242 * (non-Javadoc)
243 *
244 * @see org.junit.internal.runners.JUnit4ClassRunner#run(org.junit.runner.notification.RunNotifier)
245 */
246 @Override
247 public void run(RunNotifier notifier) {
248 startServer();
249 super.run(notifier);
250 stopServer();
251 }
252
253 private void stopServer() {
254 try {
255 server.stop();
256 } catch (Exception e) {
257 throw new RuntimeException(e);
258 }
259 }
260
261 }