/* * JBoss, Home of Professional Open Source. * Copyright 2013, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.webservices.verification; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.LinkedList; import java.util.List; import javax.jws.WebMethod; import org.jboss.as.server.deployment.reflect.ClassReflectionIndex; import org.jboss.as.server.deployment.reflect.DeploymentReflectionIndex; import org.jboss.as.webservices.logging.WSLogger; /** * Verifies the structural correctness of JSR-181 style web services. * <ul> * <li>web methods must not be static or final * <li>web methods must be public * <li>web service implementation class must not declare a finalize method * <ul> * <br> * We don't check for the @WebService annotation or whether the class is abstract, final or public because these checks are * performed by {@link org.jboss.as.webservices.util.ASHelper.isJaxwsEndpoint(ClassInfo, CompositeIndex)} from {@link * org.jboss.as.webservices.deployers.AbstractIntegrationProcessorJAXWS.deploy(DeploymentPhaseContext)}.<br> * * @author sfcoy * */ public final class JwsWebServiceEndpointVerifier { private final DeploymentReflectionIndex deploymentReflectionIndex; private final Class<?> endpointClass; private final Class<?> endpointInterfaceClass; final List<VerificationFailure> verificationFailures = new LinkedList<VerificationFailure>(); public JwsWebServiceEndpointVerifier(Class<?> endpointClass, Class<?> endpointInterfaceClass, DeploymentReflectionIndex deploymentReflectionIndex) { this.deploymentReflectionIndex = deploymentReflectionIndex; this.endpointClass = endpointClass; this.endpointInterfaceClass = endpointInterfaceClass; } public void verify() { if (endpointInterfaceClass != null) { for (Method endpointInterfaceDefinedWebMethod : endpointInterfaceDefinedWebMethods()) { verifyWebMethod(endpointInterfaceDefinedWebMethod); } } // else implicit web methods are valid by definition verifyFinalizeMethod(); } public boolean failed() { return !verificationFailures.isEmpty(); } public void logFailures() { for (VerificationFailure verificationFailure : verificationFailures) verificationFailure.logFailure(); } void verifyWebMethod(final Method endpointInterfaceDefinedWebMethod) { final Method endpointImplementationMethod = findEndpointImplMethodMatching(endpointInterfaceDefinedWebMethod); if (endpointImplementationMethod != null) { final int methodModifiers = endpointImplementationMethod.getModifiers(); final WebMethod possibleWebMethodAnnotation = endpointImplementationMethod.getAnnotation(WebMethod.class); if (possibleWebMethodAnnotation == null || !possibleWebMethodAnnotation.exclude()) { if (Modifier.isPublic(methodModifiers)) { if (Modifier.isStatic(methodModifiers) || Modifier.isFinal(methodModifiers)) { verificationFailures.add(new WebMethodIsStaticOrFinal(endpointImplementationMethod)); } } else { verificationFailures.add(new WebMethodIsNotPublic(endpointImplementationMethod)); } } } } void verifyFinalizeMethod() { ClassReflectionIndex classReflectionIndex = deploymentReflectionIndex.getClassIndex(endpointClass); Method finalizeMethod = classReflectionIndex.getMethod(void.class, "finalize"); if (finalizeMethod != null) { verificationFailures.add(new ImplementationHasFinalize()); } } Collection<Method> endpointInterfaceDefinedWebMethods() { return deploymentReflectionIndex.getClassIndex(endpointInterfaceClass).getMethods(); } Method findEndpointImplMethodMatching(final Method endpointInterfaceDefinedWebMethod) { try { return endpointClass.getMethod(endpointInterfaceDefinedWebMethod.getName(), endpointInterfaceDefinedWebMethod.getParameterTypes()); } catch (NoSuchMethodException e) { try { return endpointClass.getDeclaredMethod(endpointInterfaceDefinedWebMethod.getName(), endpointInterfaceDefinedWebMethod.getParameterTypes()); } catch (NoSuchMethodException e1) { verificationFailures.add(new WebServiceMethodNotFound(endpointInterfaceDefinedWebMethod)); } } catch (SecurityException e) { verificationFailures.add(new WebServiceMethodNotAccessible(endpointInterfaceDefinedWebMethod, e)); } return null; } abstract class VerificationFailure { abstract void logFailure(); } abstract class MethodVerificationFailure extends VerificationFailure { protected final Method failedMethod; protected MethodVerificationFailure(Method failedMethod) { this.failedMethod = failedMethod; } } final class ImplementationHasFinalize extends VerificationFailure { @Override public void logFailure() { WSLogger.ROOT_LOGGER.finalizeMethodNotAllowed(endpointClass); } } final class WebMethodIsStaticOrFinal extends MethodVerificationFailure { WebMethodIsStaticOrFinal(Method failedMethod) { super(failedMethod); } @Override public void logFailure() { WSLogger.ROOT_LOGGER.webMethodMustNotBeStaticOrFinal(failedMethod); } } final class WebMethodIsNotPublic extends MethodVerificationFailure { WebMethodIsNotPublic(Method failedMethod) { super(failedMethod); } @Override public void logFailure() { WSLogger.ROOT_LOGGER.webMethodMustBePublic(failedMethod); } } final class WebServiceMethodNotFound extends MethodVerificationFailure { WebServiceMethodNotFound(Method failedMethod) { super(failedMethod); } @Override public void logFailure() { WSLogger.ROOT_LOGGER.webServiceMethodNotFound(endpointClass, failedMethod); } } final class WebServiceMethodNotAccessible extends MethodVerificationFailure { private final SecurityException securityException; WebServiceMethodNotAccessible(Method failedMethod, SecurityException e) { super(failedMethod); this.securityException = e; } @Override public void logFailure() { WSLogger.ROOT_LOGGER.accessibleWebServiceMethodNotFound(endpointClass, failedMethod, securityException); } } }