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             * &#064;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 &#064;WebService annotaions and
114             * the test class &#064;
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    }