/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.axis2.jaxws.spi; import junit.framework.TestCase; import org.apache.axis2.jaxws.description.builder.DescriptionBuilderComposite; import org.apache.axis2.jaxws.description.impl.DescriptionUtils; import org.apache.axis2.jaxws.description.xml.handler.HandlerChainsType; import javax.jws.HandlerChain; import javax.jws.WebService; import javax.xml.namespace.QName; import javax.xml.ws.Service; import javax.xml.ws.WebServiceClient; import javax.xml.ws.handler.Handler; import javax.xml.ws.handler.HandlerResolver; import javax.xml.ws.handler.PortInfo; import javax.xml.ws.soap.SOAPBinding; import java.io.File; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Verify that handler chains specified using the HandlerChainsType in a sparse * composite are correctly applied to Services and Ports on the client requester. */ public class ClientMetadataHandlerChainTest extends TestCase { static String namespaceURI = "http://www.apache.org/test/namespace"; static String svcLocalPart = "DummyService"; static private String portLocalPart = "DummyPort"; private static int uniqueService = 0; /** * Test creating a service without a sparse composite. This verifies pre-existing default * behavior. */ public void testServiceAndPortNoComposite() { QName serviceQName = new QName(namespaceURI, svcLocalPart); QName portQName = new QName(namespaceURI, portLocalPart); Service service = Service.create(serviceQName); HandlerResolver resolver = service.getHandlerResolver(); assertNotNull(resolver); PortInfo pi = new DummyPortInfo(); List<Handler> list = resolver.getHandlerChain(pi); assertEquals(0, list.size()); ClientMetadataHandlerChainTestSEI port = service.getPort(portQName, ClientMetadataHandlerChainTestSEI.class); // Verify that ports created under the service have no handlers from the sparse composite BindingProvider bindingProvider = (BindingProvider) port; Binding binding = (Binding) bindingProvider.getBinding(); List<Handler> portHandlers = binding.getHandlerChain(); assertEquals(0, portHandlers.size()); } /** * Test creating a service with a sparse composite that contains handler configuration * information for this service delegate. Verify that the handlers are included in the * chain. */ public void testServiceWithComposite() { QName serviceQName = new QName(namespaceURI, svcLocalPart); QName portQName = new QName(namespaceURI, portLocalPart); // Create a composite with a JAXB Handler Config DescriptionBuilderComposite sparseComposite = new DescriptionBuilderComposite(); HandlerChainsType handlerChainsType = getHandlerChainsType(); sparseComposite.setHandlerChainsType(handlerChainsType); ServiceDelegate.setServiceMetadata(sparseComposite); Service service = Service.create(serviceQName); ClientMetadataHandlerChainTestSEI port = service.getPort(portQName, ClientMetadataHandlerChainTestSEI.class); // Verify the HandlerResolver on the service knows about the handlers in the sparse composite HandlerResolver resolver = service.getHandlerResolver(); assertNotNull(resolver); PortInfo pi = new DummyPortInfo(); List<Handler> list = resolver.getHandlerChain(pi); assertEquals(2, list.size()); // Verify that ports created under the service have handlers BindingProvider bindingProvider = (BindingProvider) port; Binding binding = (Binding) bindingProvider.getBinding(); List<Handler> portHandlers = binding.getHandlerChain(); assertEquals(2, portHandlers.size()); assertTrue(containSameHandlers(portHandlers, list)); // Verify that a subsequent port are different and that they also gets the correct handlers ClientMetadataHandlerChainTestSEI port2 = service.getPort(portQName, ClientMetadataHandlerChainTestSEI.class); BindingProvider bindingProvider2 = (BindingProvider) port2; Binding binding2 = (Binding) bindingProvider2.getBinding(); List<Handler> portHandlers2 = binding2.getHandlerChain(); assertNotSame(port, port2); assertEquals(2, portHandlers2.size()); assertTrue(containSameHandlers(portHandlers2, list)); } /** * Set a sparse composite on a specific Port. Verify that instances of that Port have the * correct handlers associated and other Ports do not. */ public void testPortWithComposite() { QName serviceQName = new QName(namespaceURI, svcLocalPart); QName portQName = new QName(namespaceURI, portLocalPart); Service service = Service.create(serviceQName); // Create a composite with a JAXB Handler Config DescriptionBuilderComposite sparseComposite = new DescriptionBuilderComposite(); HandlerChainsType handlerChainsType = getHandlerChainsType(); sparseComposite.setHandlerChainsType(handlerChainsType); ServiceDelegate.setPortMetadata(sparseComposite); ClientMetadataHandlerChainTestSEI port = service.getPort(portQName, ClientMetadataHandlerChainTestSEI.class); // Verify the HandlerResolver on the service knows about the handlers in the sparse composite HandlerResolver resolver = service.getHandlerResolver(); assertNotNull(resolver); PortInfo pi = new DummyPortInfo(); List<Handler> list = resolver.getHandlerChain(pi); assertEquals(2, list.size()); // Verify that the port created with the sparse metadata has those handlers BindingProvider bindingProvider = (BindingProvider) port; Binding binding = (Binding) bindingProvider.getBinding(); List<Handler> portHandlers = binding.getHandlerChain(); assertEquals(2, portHandlers.size()); assertTrue(containSameHandlers(portHandlers, list)); // Verify that a creating another instance of the same port also gets those handlers ClientMetadataHandlerChainTestSEI port2 = service.getPort(portQName, ClientMetadataHandlerChainTestSEI.class); BindingProvider bindingProvider2 = (BindingProvider) port2; Binding binding2 = (Binding) bindingProvider2.getBinding(); List<Handler> portHandlers2 = binding2.getHandlerChain(); assertNotSame(port, port2); assertEquals(2, portHandlers2.size()); assertTrue(containSameHandlers(portHandlers2, list)); // Verify that createing a different port doesn't get the handlers QName portQName3 = new QName(namespaceURI, portLocalPart + "3"); ClientMetadataHandlerChainTestSEI port3 = service.getPort(portQName3, ClientMetadataHandlerChainTestSEI.class); BindingProvider bindingProvider3 = (BindingProvider) port3; Binding binding3 = (Binding) bindingProvider3.getBinding(); List<Handler> portHandlers3 = binding3.getHandlerChain(); assertEquals(0, portHandlers3.size()); // Verify setting the metadata on a different port (a different QName) will get handlers. QName portQName4 = new QName(namespaceURI, portLocalPart + "4"); ServiceDelegate.setPortMetadata(sparseComposite); ClientMetadataHandlerChainTestSEI port4 = service.getPort(portQName4, ClientMetadataHandlerChainTestSEI.class); BindingProvider bindingProvider4 = (BindingProvider) port4; Binding binding4 = (Binding) bindingProvider4.getBinding(); List<Handler> portHandlers4 = binding4.getHandlerChain(); assertEquals(2, portHandlers4.size()); // Verify the service handler resolver knows about boths sets of handlers // attached to the two different port QNames and none are attached for the third port List<Handler> listForPort = resolver.getHandlerChain(pi); assertEquals(2, listForPort.size()); PortInfo pi4 = new DummyPortInfo(portQName4); List<Handler> listForPort4 = resolver.getHandlerChain(pi4); assertEquals(2, listForPort4.size()); PortInfo pi3 = new DummyPortInfo(portQName3); List<Handler> listForPort3 = resolver.getHandlerChain(pi3); assertEquals(0, listForPort3.size()); } /** * Verify that handlers specified in a sparse compoiste on the service are only associated with * that specific service delegate (i.e. Service instance), even if the QNames are the same * across two instances of a Service. */ public void testMultipleServiceDelgatesServiceComposite() { try { // Need to cache the ServiceDescriptions so that they are shared // across the two instances of the same Service. ClientMetadataTest.installCachingFactory(); QName serviceQName = new QName(namespaceURI, svcLocalPart); PortInfo pi = new DummyPortInfo(); // Create a Service specifying a sparse composite and verify the // ports under that service get the correct handlers associated. DescriptionBuilderComposite sparseComposite = new DescriptionBuilderComposite(); HandlerChainsType handlerChainsType = getHandlerChainsType(); sparseComposite.setHandlerChainsType(handlerChainsType); ServiceDelegate.setServiceMetadata(sparseComposite); Service service1 = Service.create(serviceQName); // Create a second instance of the same Service, but without // metadata. Ports created under that service should not get handler's associated. Service service2 = Service.create(serviceQName); // No ports created yet, so there should be no relevant handler // chains. HandlerResolver resolver1 = service1.getHandlerResolver(); List<Handler> list1 = resolver1.getHandlerChain(pi); assertEquals(0, list1.size()); // Create the port, it should get handlers. QName portQName1 = new QName(namespaceURI, portLocalPart); ClientMetadataHandlerChainTestSEI port1 = service1.getPort(portQName1, ClientMetadataHandlerChainTestSEI.class); BindingProvider bindingProvider1 = (BindingProvider) port1; Binding binding1 = (Binding) bindingProvider1.getBinding(); List<Handler> portHandlers1 = binding1.getHandlerChain(); assertEquals(2, portHandlers1.size()); // Refresh the handler list from the resolver after the port is created list1 = resolver1.getHandlerChain(pi); assertTrue(containSameHandlers(portHandlers1, list1)); // Make sure the 2nd Service instance doesn't have handlers // associated with it HandlerResolver resolver2 = service2.getHandlerResolver(); List<Handler> list2 = resolver2.getHandlerChain(pi); assertEquals(0, list2.size()); // Make sure the same port created under the 2nd service also // doesn't have handlers ClientMetadataHandlerChainTestSEI port2 = service2.getPort(portQName1, ClientMetadataHandlerChainTestSEI.class); BindingProvider bindingProvider2 = (BindingProvider) port2; Binding binding2 = (Binding) bindingProvider2.getBinding(); List<Handler> portHandlers2 = binding2.getHandlerChain(); assertEquals(0, portHandlers2.size()); } finally { ClientMetadataTest.restoreOriginalFactory(); } } /** * Verify that handlers specified in a sparse compoiste on the port are only associated with * that port on that specific service delegate (i.e. Service instance), even if the QNames are the same * across two instances of a Service. */ public void testMultipleServiceDelgatesPortComposite() { try { // Need to cache the ServiceDescriptions so that they are shared // across the two instances of the same Service. ClientMetadataTest.installCachingFactory(); QName serviceQName = new QName(namespaceURI, svcLocalPart); PortInfo pi = new DummyPortInfo(); // Create two instances of the same Service Service service1 = Service.create(serviceQName); Service service2 = Service.create(serviceQName); // No ports created yet, so there should be no relevant handler // chains. HandlerResolver resolver1 = service1.getHandlerResolver(); List<Handler> list1 = resolver1.getHandlerChain(pi); assertEquals(0, list1.size()); // Create a Port specifying a sparse composite and verify the // port gets the correct handlers associated. DescriptionBuilderComposite sparseComposite = new DescriptionBuilderComposite(); HandlerChainsType handlerChainsType = getHandlerChainsType(); sparseComposite.setHandlerChainsType(handlerChainsType); ServiceDelegate.setPortMetadata(sparseComposite); QName portQName1 = new QName(namespaceURI, portLocalPart); ClientMetadataHandlerChainTestSEI port1 = service1.getPort(portQName1, ClientMetadataHandlerChainTestSEI.class); BindingProvider bindingProvider1 = (BindingProvider) port1; Binding binding1 = (Binding) bindingProvider1.getBinding(); List<Handler> portHandlers1 = binding1.getHandlerChain(); assertEquals(2, portHandlers1.size()); // Refresh the handler list from the resolver after the port is created list1 = resolver1.getHandlerChain(pi); assertTrue(containSameHandlers(portHandlers1, list1)); // Make sure the 2nd Service instance doesn't have handlers // associated with it HandlerResolver resolver2 = service2.getHandlerResolver(); List<Handler> list2 = resolver2.getHandlerChain(pi); assertEquals(0, list2.size()); // Make sure the same port created under the 2nd service also // doesn't have handlers ClientMetadataHandlerChainTestSEI port2 = service2.getPort(portQName1, ClientMetadataHandlerChainTestSEI.class); BindingProvider bindingProvider2 = (BindingProvider) port2; Binding binding2 = (Binding) bindingProvider2.getBinding(); List<Handler> portHandlers2 = binding2.getHandlerChain(); assertEquals(0, portHandlers2.size()); } finally { ClientMetadataTest.restoreOriginalFactory(); } } /** * Verify that the original functionality of specifying a HandlerChain annotation with a * file member works as it should. */ public void testHandlerChainOnSEI() { QName serviceQN = new QName(namespaceURI, svcLocalPart); Service service = Service.create(serviceQN); ClientMetadataHandlerChainTestSEIWithHC port = service.getPort(ClientMetadataHandlerChainTestSEIWithHC.class); BindingProvider bindingProvider = (BindingProvider) port; Binding binding = (Binding) bindingProvider.getBinding(); List<Handler> portHandlers = binding.getHandlerChain(); assertEquals(1, portHandlers.size()); assertTrue(containsHandlerChainAnnotationHandlers(portHandlers)); } /** * Verify that handler information in a sparse composite on the Port will override any handler chain * annotation on the SEI. */ public void testSEIHandlerChainOverrideOnPort() { QName serviceQN = new QName(namespaceURI, svcLocalPart + uniqueService++); Service service = Service.create(serviceQN); // The SEI has a HandlerChain annotation, but the sparse metadata should override it DescriptionBuilderComposite sparseComposite = new DescriptionBuilderComposite(); HandlerChainsType handlerChainsType = getHandlerChainsType(); sparseComposite.setHandlerChainsType(handlerChainsType); ServiceDelegate.setPortMetadata(sparseComposite); ClientMetadataHandlerChainTestSEIWithHC port = service.getPort(ClientMetadataHandlerChainTestSEIWithHC.class); BindingProvider bindingProvider = (BindingProvider) port; Binding binding = (Binding) bindingProvider.getBinding(); List<Handler> portHandlers = binding.getHandlerChain(); assertEquals(2, portHandlers.size()); assertTrue(containsSparseCompositeHandlers(portHandlers)); } /** * Verify that handler information in a sparse composite on the Service will override any handler chain * annotation on the SEI. */ public void testSEIHandlerChainOverrideOnService() { QName serviceQN = new QName(namespaceURI, svcLocalPart + uniqueService++); // The SEI has a HandlerChain annotation, but the sparse metadata should override it DescriptionBuilderComposite sparseComposite = new DescriptionBuilderComposite(); HandlerChainsType handlerChainsType = getHandlerChainsType(); sparseComposite.setHandlerChainsType(handlerChainsType); ServiceDelegate.setServiceMetadata(sparseComposite); Service service = Service.create(serviceQN); ClientMetadataHandlerChainTestSEIWithHC port = service.getPort(ClientMetadataHandlerChainTestSEIWithHC.class); BindingProvider bindingProvider = (BindingProvider) port; Binding binding = (Binding) bindingProvider.getBinding(); List<Handler> portHandlers = binding.getHandlerChain(); assertEquals(2, portHandlers.size()); assertTrue(containsSparseCompositeHandlers(portHandlers)); } /** * Set different composites on the Service and the Port that specify different * HandlerChainsType values. */ public void testCompositeOnServiceAndPort() { QName serviceQN = new QName(namespaceURI, svcLocalPart + uniqueService++); // Create a service with a composite specifying handlers DescriptionBuilderComposite sparseComposite = new DescriptionBuilderComposite(); HandlerChainsType handlerChainsType = getHandlerChainsType(); sparseComposite.setHandlerChainsType(handlerChainsType); ServiceDelegate.setServiceMetadata(sparseComposite); Service service = Service.create(serviceQN); // Create a port with a composite specifying different handlers DescriptionBuilderComposite portComposite = new DescriptionBuilderComposite(); HandlerChainsType portHandlerChainsType = getHandlerChainsType("ClientMetadataHandlerChainTest.xml"); portComposite.setHandlerChainsType(portHandlerChainsType); ServiceDelegate.setPortMetadata(portComposite); ClientMetadataHandlerChainTestSEI port = service.getPort(ClientMetadataHandlerChainTestSEI.class); BindingProvider bindingProvider = (BindingProvider) port; Binding binding = (Binding) bindingProvider.getBinding(); List<Handler> portHandlers = binding.getHandlerChain(); // If there is a HandlerChainsType composite specified on both the Service and the Port, // then the composite specified on the Port should be the one used to associate the // handlers for that Port. assertEquals(1, portHandlers.size()); assertTrue(containsHandlerChainAnnotationHandlers(portHandlers)); } /** * Verfiy that a HandlerChain annotation on the Service is associated with the Port */ public void testGeneratedServiceWithHC() { ClientMetadataHandlerChainTestServiceWithHC service = new ClientMetadataHandlerChainTestServiceWithHC(); ClientMetadataHandlerChainTestSEI port = service.getPort(ClientMetadataHandlerChainTestSEI.class); BindingProvider bindingProvider = (BindingProvider) port; Binding binding = (Binding) bindingProvider.getBinding(); List<Handler> portHandlers = binding.getHandlerChain(); assertEquals(1, portHandlers.size()); assertTrue(containsHandlerChainAnnotationHandlers(portHandlers)); } /** * Verfiy that given a HandlerChain annotation on the Service and a Port and a sparse composite * on the Port associates the handlers from the sparse composite on the Port. */ public void testGeneratedServiceWithHCPortOverride() { ClientMetadataHandlerChainTestServiceWithHC service = new ClientMetadataHandlerChainTestServiceWithHC(); // Set a HandlerChainsType on the sparse composite for the Port creation; it should override the // HandlerChain annotation on the Service. DescriptionBuilderComposite sparseComposite = new DescriptionBuilderComposite(); HandlerChainsType handlerChainsType = getHandlerChainsType(); sparseComposite.setHandlerChainsType(handlerChainsType); ServiceDelegate.setPortMetadata(sparseComposite); ClientMetadataHandlerChainTestSEI port = service.getPort(ClientMetadataHandlerChainTestSEI.class); BindingProvider bindingProvider = (BindingProvider) port; Binding binding = (Binding) bindingProvider.getBinding(); List<Handler> portHandlers = binding.getHandlerChain(); assertEquals(2, portHandlers.size()); assertTrue(containsSparseCompositeHandlers(portHandlers)); } // ============================================================================================= // Helper methods and classes // ============================================================================================= private boolean containsSparseCompositeHandlers(List<Handler> handlerList) { List<Class> inputHandlerClasses = handlerClasses(handlerList); // These are the handlers defined in the HandlerChainsType placed on the sparse composite List<Class> compositeHandlerClasses = new ArrayList<Class>(); compositeHandlerClasses.add(org.apache.axis2.jaxws.spi.handler.DummySOAPHandler.class); compositeHandlerClasses.add(org.apache.axis2.jaxws.spi.handler.DummyLogicalHandler.class); if (inputHandlerClasses.size() != compositeHandlerClasses.size()) { return false; } if (inputHandlerClasses.containsAll(compositeHandlerClasses)) { return true; } else { return false; } } /** * Answer if the List contains the same handlers as defined in the SEI * via the HandlerChain.file annotation memeber. * * @param portHandlers List of handlers * @return true if the list matches what was defined on the SEI via the * HandlerChain annotation; false otherwise. */ private boolean containsHandlerChainAnnotationHandlers(List<Handler> portHandlers) { List<Class> portHandlerClasses = handlerClasses(portHandlers); List<Class> seiHandlerClasses = new ArrayList<Class>(); seiHandlerClasses.add(ClientMetadataHandlerChainHandler.class); if (portHandlerClasses.size() != seiHandlerClasses.size()) { return false; } if (portHandlerClasses.containsAll(seiHandlerClasses)) { return true; } else { return false; } } /** * Answer if two List<Handler> arguments contain the same handler Class files. * @param list1 * @param list2 * @return */ private boolean containSameHandlers(List<Handler> list1, List<Handler> list2) { if (list1.size() != list2.size()) { return false; } List<Class> list1HandlerClasses = handlerClasses(list1); List<Class> list2HandlerClasses = handlerClasses(list2); if (list1HandlerClasses.containsAll(list2HandlerClasses)) { return true; } else { return false; } } private List<Class> handlerClasses(List<Handler> listOfHandlers) { List<Class> handlerClasses = new ArrayList<Class>(); Iterator<Handler> handlerIterator = listOfHandlers.iterator(); while (handlerIterator.hasNext()) { handlerClasses.add(handlerIterator.next().getClass()); } return handlerClasses; } private HandlerChainsType getHandlerChainsType() { return getHandlerChainsType("handler.xml"); } private HandlerChainsType getHandlerChainsType(String fileName) { InputStream is = getXMLFileStream(fileName); assertNotNull(is); HandlerChainsType returnHCT = DescriptionUtils.loadHandlerChains(is, this.getClass().getClassLoader()); assertNotNull(returnHCT); return returnHCT; } private InputStream getXMLFileStream(String fileName) { InputStream is = null; String configLoc = null; try { String sep = "/"; configLoc = sep + "test-resources" + sep + "configuration" + sep + "handlers" + sep + fileName; String baseDir = new File(System.getProperty("basedir",".")).getCanonicalPath(); is = new File(baseDir + configLoc).toURL().openStream(); } catch(Exception e) { e.printStackTrace(); } return is; } public class DummyPortInfo implements PortInfo { private QName portQN; private QName serviceQN; public DummyPortInfo() { this.portQN = new QName("http://www.apache.org/test/namespace", "DummyPort"); this.serviceQN = new QName("http://www.apache.org/test/namespace", "DummyService"); } public DummyPortInfo(QName portQN) { this(); this.portQN = portQN; } public String getBindingID() { return SOAPBinding.SOAP11HTTP_BINDING; } public QName getPortName() { return portQN; } public QName getServiceName() { return serviceQN; } } } @WebService interface ClientMetadataHandlerChainTestSEI { public String echo(String toEcho); } @WebService @HandlerChain(file="ClientMetadataHandlerChainTest.xml") interface ClientMetadataHandlerChainTestSEIWithHC { public String echo(String toEcho); } @WebServiceClient @HandlerChain(file="ClientMetadataHandlerChainTest.xml") class ClientMetadataHandlerChainTestServiceWithHC extends javax.xml.ws.Service { public ClientMetadataHandlerChainTestServiceWithHC() { super(null, new QName(ClientMetadataHandlerChainTest.namespaceURI, ClientMetadataHandlerChainTest.svcLocalPart)); } public ClientMetadataHandlerChainTestServiceWithHC(URL wsdlLocation, QName serviceName) { super(wsdlLocation, serviceName); } }