001 /** 002 * Copyright 2005-2011 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.rice.test.remote; 017 018 import org.apache.commons.logging.Log; 019 import org.apache.commons.logging.LogFactory; 020 import org.apache.cxf.endpoint.Client; 021 import org.apache.cxf.frontend.ClientProxy; 022 import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; 023 import org.kuali.rice.ksb.impl.cxf.interceptors.ImmutableCollectionsInInterceptor; 024 025 import javax.jws.WebService; 026 import javax.xml.ws.Endpoint; 027 028 /** 029 * Harness used to hold a reference to an endpoint that is published to support remote tests. Tests using 030 * this harness should pass in a @WebService annotated interface class and an object of an implementing class 031 * of that interface to the publishEndpointAndReturnProxy method in @Before or setUp methods used in tests. 032 * <p/> 033 * The endpoint will always be published at a URL like http://localhost:1025/service where the port number changes 034 * each time publishEndpointAndReturnProxy is called and guarantees that an open port is used. 035 * <p/ 036 * After each test is run, stopEndPoint should be called in @After or tearDown methods in order to unpublish the 037 * endpoint. 038 * <p/> 039 * 040 */ 041 public class RemoteTestHarness { 042 043 private static final Log LOG = LogFactory.getLog(RemoteTestHarness.class); 044 045 private static String ENDPOINT_ROOT = "http://localhost"; //Default URL 046 private static String ENDPOINT_PATH = "/service"; 047 048 private Endpoint endpoint; 049 050 @SuppressWarnings("unchecked") 051 /** 052 * Creates a published endpoint from the passed in serviceImplementation and also returns a proxy implementation 053 * of the passed in interface for clients to use to hit the created endpoint. 054 */ 055 public <T> T publishEndpointAndReturnProxy(Class<T> jaxWsAnnotatedInterface, T serviceImplementation) { 056 if (jaxWsAnnotatedInterface.isInterface() && 057 jaxWsAnnotatedInterface.getAnnotation(WebService.class) != null && 058 jaxWsAnnotatedInterface.isInstance(serviceImplementation)) { 059 060 String endpointUrl = getAvailableEndpointUrl(); 061 LOG.info("Publishing service to: " + endpointUrl); 062 endpoint = Endpoint.publish(endpointUrl, serviceImplementation); 063 064 JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); 065 factory.setServiceClass(jaxWsAnnotatedInterface); 066 factory.setAddress(endpointUrl); 067 068 T serviceProxy = (T) factory.create(); 069 070 /* Add the ImmutableCollectionsInInterceptor to mimic interceptors added in the KSB */ 071 Client cxfClient = ClientProxy.getClient(serviceProxy); 072 cxfClient.getInInterceptors().add(new ImmutableCollectionsInInterceptor()); 073 074 return serviceProxy; 075 } else { 076 throw new IllegalArgumentException("Passed in interface class type must be annotated with @WebService " + 077 "and object reference must be an implementing class of that interface."); 078 079 } 080 } 081 082 /** 083 * Stops and makes an internal endpoint unpublished if it was previously published. 084 * Otherwise, this method is a no-op. 085 */ 086 public void stopEndpoint() { 087 if (endpoint != null) { 088 endpoint.stop(); 089 } 090 } 091 092 private String getAvailableEndpointUrl() { 093 String port = Integer.toString(AvailablePortFinder.getNextAvailable()); 094 return ENDPOINT_ROOT + ":" + port + ENDPOINT_PATH; 095 } 096 }