1 /* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.internal.ws.processor.modeler.annotation; 27 28 import com.sun.istack.internal.logging.Logger; 29 import com.sun.tools.internal.ws.processor.generator.GeneratorUtil; 30 import com.sun.tools.internal.ws.processor.modeler.ModelerException; 31 import com.sun.tools.internal.ws.resources.WebserviceapMessages; 32 import com.sun.tools.internal.ws.wscompile.AbortException; 33 import com.sun.tools.internal.ws.wscompile.WsgenOptions; 34 35 import javax.annotation.processing.AbstractProcessor; 36 import javax.annotation.processing.ProcessingEnvironment; 37 import javax.annotation.processing.RoundEnvironment; 38 import javax.annotation.processing.SupportedAnnotationTypes; 39 import javax.annotation.processing.SupportedOptions; 40 import javax.jws.WebService; 41 import javax.lang.model.SourceVersion; 42 import javax.lang.model.element.Element; 43 import javax.lang.model.element.ElementKind; 44 import javax.lang.model.element.Name; 45 import javax.lang.model.element.TypeElement; 46 import javax.lang.model.type.TypeMirror; 47 import javax.lang.model.util.ElementFilter; 48 import javax.tools.Diagnostic; 49 import javax.xml.ws.Holder; 50 import javax.xml.ws.WebServiceProvider; 51 import java.io.ByteArrayOutputStream; 52 import java.io.File; 53 import java.io.PrintStream; 54 import java.lang.reflect.Method; 55 import java.rmi.Remote; 56 import java.rmi.RemoteException; 57 import java.util.ArrayList; 58 import java.util.Collection; 59 import java.util.HashSet; 60 import java.util.Scanner; 61 import java.util.Set; 62 import java.util.logging.Level; 63 64 /** 65 * WebServiceAp is a AnnotationProcessor for processing javax.jws.* and 66 * javax.xml.ws.* annotations. This class is used either by the WsGen (CompileTool) tool or 67 * indirectly when invoked by javac. 68 * 69 * @author WS Development Team 70 */ 71 @SupportedAnnotationTypes({ 72 "javax.jws.HandlerChain", 73 "javax.jws.Oneway", 74 "javax.jws.WebMethod", 75 "javax.jws.WebParam", 76 "javax.jws.WebResult", 77 "javax.jws.WebService", 78 "javax.jws.soap.InitParam", 79 "javax.jws.soap.SOAPBinding", 80 "javax.jws.soap.SOAPMessageHandler", 81 "javax.jws.soap.SOAPMessageHandlers", 82 "javax.xml.ws.BindingType", 83 "javax.xml.ws.RequestWrapper", 84 "javax.xml.ws.ResponseWrapper", 85 "javax.xml.ws.ServiceMode", 86 "javax.xml.ws.WebEndpoint", 87 "javax.xml.ws.WebFault", 88 "javax.xml.ws.WebServiceClient", 89 "javax.xml.ws.WebServiceProvider", 90 "javax.xml.ws.WebServiceRef" 91 }) 92 @SupportedOptions({WebServiceAp.DO_NOT_OVERWRITE, WebServiceAp.IGNORE_NO_WEB_SERVICE_FOUND_WARNING}) 93 public class WebServiceAp extends AbstractProcessor implements ModelBuilder { 94 95 private static final Logger LOGGER = Logger.getLogger(WebServiceAp.class); 96 97 public static final String DO_NOT_OVERWRITE = "doNotOverWrite"; 98 public static final String IGNORE_NO_WEB_SERVICE_FOUND_WARNING = "ignoreNoWebServiceFoundWarning"; 99 100 private WsgenOptions options; 101 protected AnnotationProcessorContext context; 102 private File sourceDir; 103 private boolean doNotOverWrite; 104 private boolean ignoreNoWebServiceFoundWarning = false; 105 private TypeElement remoteElement; 106 private TypeMirror remoteExceptionElement; 107 private TypeMirror exceptionElement; 108 private TypeMirror runtimeExceptionElement; 109 private TypeElement defHolderElement; 110 private boolean isCommandLineInvocation; 111 private PrintStream out; 112 private Collection<TypeElement> processedTypeElements = new HashSet<TypeElement>(); 113 114 public WebServiceAp() { 115 this.context = new AnnotationProcessorContext(); 116 } 117 118 public WebServiceAp(WsgenOptions options, PrintStream out) { 119 this.options = options; 120 this.sourceDir = (options != null) ? options.sourceDir : null; 121 this.doNotOverWrite = (options != null) && options.doNotOverWrite; 122 this.context = new AnnotationProcessorContext(); 123 this.out = out; 124 } 125 126 @Override 127 public synchronized void init(ProcessingEnvironment processingEnv) { 128 super.init(processingEnv); 129 remoteElement = processingEnv.getElementUtils().getTypeElement(Remote.class.getName()); 130 remoteExceptionElement = processingEnv.getElementUtils().getTypeElement(RemoteException.class.getName()).asType(); 131 exceptionElement = processingEnv.getElementUtils().getTypeElement(Exception.class.getName()).asType(); 132 runtimeExceptionElement = processingEnv.getElementUtils().getTypeElement(RuntimeException.class.getName()).asType(); 133 defHolderElement = processingEnv.getElementUtils().getTypeElement(Holder.class.getName()); 134 if (options == null) { 135 options = new WsgenOptions(); 136 137 out = new PrintStream(new ByteArrayOutputStream()); 138 139 doNotOverWrite = getOption(DO_NOT_OVERWRITE); 140 ignoreNoWebServiceFoundWarning = getOption(IGNORE_NO_WEB_SERVICE_FOUND_WARNING); 141 142 String classDir = parseArguments(); 143 String property = System.getProperty("java.class.path"); 144 options.classpath = classDir + File.pathSeparator + (property != null ? property : ""); 145 isCommandLineInvocation = true; 146 } 147 options.filer = processingEnv.getFiler(); 148 } 149 150 private String parseArguments() { 151 // let's try to parse JavacOptions 152 153 String classDir = null; 154 try { 155 ClassLoader cl = WebServiceAp.class.getClassLoader(); 156 Class javacProcessingEnvironmentClass = Class.forName("com.sun.tools.javac.processing.JavacProcessingEnvironment", false, cl); 157 if (javacProcessingEnvironmentClass.isInstance(processingEnv)) { 158 Method getContextMethod = javacProcessingEnvironmentClass.getDeclaredMethod("getContext"); 159 Object tmpContext = getContextMethod.invoke(processingEnv); 160 Class optionsClass = Class.forName("com.sun.tools.javac.util.Options", false, cl); 161 Class contextClass = Class.forName("com.sun.tools.javac.util.Context", false, cl); 162 Method instanceMethod = optionsClass.getDeclaredMethod("instance", new Class[]{contextClass}); 163 Object tmpOptions = instanceMethod.invoke(null, tmpContext); 164 if (tmpOptions != null) { 165 Method getMethod = optionsClass.getDeclaredMethod("get", new Class[]{String.class}); 166 Object result = getMethod.invoke(tmpOptions, "-s"); // todo: we have to check for -d also 167 if (result != null) { 168 classDir = (String) result; 169 } 170 this.options.verbose = getMethod.invoke(tmpOptions, "-verbose") != null; 171 } 172 } 173 } catch (Exception e) { 174 /// some Error was here - problems with reflection or security 175 processWarning(WebserviceapMessages.WEBSERVICEAP_PARSING_JAVAC_OPTIONS_ERROR()); 176 report(e.getMessage()); 177 } 178 179 if (classDir == null) { // some error within reflection block 180 String property = System.getProperty("sun.java.command"); 181 if (property != null) { 182 Scanner scanner = new Scanner(property); 183 boolean sourceDirNext = false; 184 while (scanner.hasNext()) { 185 String token = scanner.next(); 186 if (sourceDirNext) { 187 classDir = token; 188 sourceDirNext = false; 189 } else if ("-verbose".equals(token)) { 190 options.verbose = true; 191 } else if ("-s".equals(token)) { 192 sourceDirNext = true; 193 } 194 } 195 } 196 } 197 if (classDir != null) { 198 sourceDir = new File(classDir); 199 } 200 return classDir; 201 } 202 203 private boolean getOption(String key) { 204 String value = processingEnv.getOptions().get(key); 205 if (value != null) { 206 return Boolean.valueOf(value); 207 } 208 return false; 209 } 210 211 @Override 212 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 213 if (context.getRound() != 1) { 214 return true; 215 } 216 context.incrementRound(); 217 WebService webService; 218 WebServiceProvider webServiceProvider; 219 WebServiceVisitor webServiceVisitor = new WebServiceWrapperGenerator(this, context); 220 boolean processedEndpoint = false; 221 Collection<TypeElement> classes = new ArrayList<TypeElement>(); 222 filterClasses(classes, roundEnv.getRootElements()); 223 for (TypeElement element : classes) { 224 webServiceProvider = element.getAnnotation(WebServiceProvider.class); 225 webService = element.getAnnotation(WebService.class); 226 if (webServiceProvider != null) { 227 if (webService != null) { 228 processError(WebserviceapMessages.WEBSERVICEAP_WEBSERVICE_AND_WEBSERVICEPROVIDER(element.getQualifiedName())); 229 } 230 processedEndpoint = true; 231 } 232 233 if (webService == null) { 234 continue; 235 } 236 237 element.accept(webServiceVisitor, null); 238 processedEndpoint = true; 239 } 240 if (!processedEndpoint) { 241 if (isCommandLineInvocation) { 242 if (!ignoreNoWebServiceFoundWarning) { 243 processWarning(WebserviceapMessages.WEBSERVICEAP_NO_WEBSERVICE_ENDPOINT_FOUND()); 244 } 245 } else { 246 processError(WebserviceapMessages.WEBSERVICEAP_NO_WEBSERVICE_ENDPOINT_FOUND()); 247 } 248 } 249 return true; 250 } 251 252 private void filterClasses(Collection<TypeElement> classes, Collection<? extends Element> elements) { 253 for (Element element : elements) { 254 if (element.getKind().equals(ElementKind.CLASS)) { 255 classes.add((TypeElement) element); 256 filterClasses(classes, ElementFilter.typesIn(element.getEnclosedElements())); 257 } 258 } 259 } 260 261 @Override 262 public void processWarning(String message) { 263 if (isCommandLineInvocation) { 264 processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, message); 265 } else { 266 report(message); 267 } 268 } 269 270 protected void report(String msg) { 271 if (out == null) { 272 if (LOGGER.isLoggable(Level.FINE)) { 273 LOGGER.log(Level.FINE, "No output set for web service annotation processor reporting."); 274 } 275 return; 276 } 277 out.println(msg); 278 out.flush(); 279 } 280 281 @Override 282 public void processError(String message) { 283 if (isCommandLineInvocation) { 284 processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, message); 285 throw new AbortException(); 286 } else { 287 throw new ModelerException(message); 288 } 289 } 290 291 @Override 292 public void processError(String message, Element element) { 293 if (isCommandLineInvocation) { 294 processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, message, element); 295 } else { 296 throw new ModelerException(message); 297 } 298 } 299 300 @Override 301 public boolean canOverWriteClass(String className) { 302 return !((doNotOverWrite && GeneratorUtil.classExists(options, className))); 303 } 304 305 @Override 306 public File getSourceDir() { 307 return sourceDir; 308 } 309 310 @Override 311 public boolean isRemote(TypeElement typeElement) { 312 return processingEnv.getTypeUtils().isSubtype(typeElement.asType(), remoteElement.asType()); 313 } 314 315 @Override 316 public boolean isServiceException(TypeMirror typeMirror) { 317 return processingEnv.getTypeUtils().isSubtype(typeMirror, exceptionElement) 318 && !processingEnv.getTypeUtils().isSubtype(typeMirror, runtimeExceptionElement) 319 && !processingEnv.getTypeUtils().isSubtype(typeMirror, remoteExceptionElement); 320 } 321 322 @Override 323 public TypeMirror getHolderValueType(TypeMirror type) { 324 return TypeModeler.getHolderValueType(type, defHolderElement, processingEnv); 325 } 326 327 @Override 328 public boolean checkAndSetProcessed(TypeElement typeElement) { 329 if (!processedTypeElements.contains(typeElement)) { 330 processedTypeElements.add(typeElement); 331 return false; 332 } 333 return true; 334 } 335 336 @Override 337 public void log(String message) { 338 if (options != null && options.verbose) { 339 message = new StringBuilder().append('[').append(message).append(']').toString(); // "[%s]" 340 processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message); 341 } 342 } 343 344 @Override 345 public WsgenOptions getOptions() { 346 return options; 347 } 348 349 @Override 350 public ProcessingEnvironment getProcessingEnvironment() { 351 return processingEnv; 352 } 353 354 @Override 355 public String getOperationName(Name messageName) { 356 return messageName != null ? messageName.toString() : null; 357 } 358 359 @Override 360 public SourceVersion getSupportedSourceVersion() { 361 return SourceVersion.latest(); 362 } 363 }