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 }