1/* 2 * Copyright (c) 2010, 2016, 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 26package com.sun.tools.internal.ws.processor.modeler.annotation; 27 28import com.sun.istack.internal.logging.Logger; 29import com.sun.tools.internal.ws.processor.generator.GeneratorUtil; 30import com.sun.tools.internal.ws.processor.modeler.ModelerException; 31import com.sun.tools.internal.ws.resources.WebserviceapMessages; 32import com.sun.tools.internal.ws.wscompile.AbortException; 33import com.sun.tools.internal.ws.wscompile.WsgenOptions; 34 35import javax.annotation.processing.AbstractProcessor; 36import javax.annotation.processing.ProcessingEnvironment; 37import javax.annotation.processing.RoundEnvironment; 38import javax.annotation.processing.SupportedAnnotationTypes; 39import javax.annotation.processing.SupportedOptions; 40import javax.jws.WebService; 41import javax.lang.model.SourceVersion; 42import javax.lang.model.element.Element; 43import javax.lang.model.element.ElementKind; 44import javax.lang.model.element.Name; 45import javax.lang.model.element.TypeElement; 46import javax.lang.model.type.TypeMirror; 47import javax.lang.model.util.ElementFilter; 48import javax.tools.Diagnostic; 49import javax.xml.ws.Holder; 50import javax.xml.ws.WebServiceProvider; 51import java.io.ByteArrayOutputStream; 52import java.io.File; 53import java.io.PrintStream; 54import java.util.ArrayList; 55import java.util.Collection; 56import java.util.HashSet; 57import java.util.Set; 58import java.util.logging.Level; 59 60/** 61 * WebServiceAp is a AnnotationProcessor for processing javax.jws.* and 62 * javax.xml.ws.* annotations. This class is used either by the WsGen (CompileTool) tool or 63 * indirectly when invoked by javac. 64 * 65 * @author WS Development Team 66 */ 67@SupportedAnnotationTypes({ 68 "javax.jws.HandlerChain", 69 "javax.jws.Oneway", 70 "javax.jws.WebMethod", 71 "javax.jws.WebParam", 72 "javax.jws.WebResult", 73 "javax.jws.WebService", 74 "javax.jws.soap.InitParam", 75 "javax.jws.soap.SOAPBinding", 76 "javax.jws.soap.SOAPMessageHandler", 77 "javax.jws.soap.SOAPMessageHandlers", 78 "javax.xml.ws.BindingType", 79 "javax.xml.ws.RequestWrapper", 80 "javax.xml.ws.ResponseWrapper", 81 "javax.xml.ws.ServiceMode", 82 "javax.xml.ws.WebEndpoint", 83 "javax.xml.ws.WebFault", 84 "javax.xml.ws.WebServiceClient", 85 "javax.xml.ws.WebServiceProvider", 86 "javax.xml.ws.WebServiceRef" 87}) 88@SupportedOptions({WebServiceAp.DO_NOT_OVERWRITE, WebServiceAp.IGNORE_NO_WEB_SERVICE_FOUND_WARNING, WebServiceAp.VERBOSE}) 89public class WebServiceAp extends AbstractProcessor implements ModelBuilder { 90 91 private static final Logger LOGGER = Logger.getLogger(WebServiceAp.class); 92 93 public static final String DO_NOT_OVERWRITE = "doNotOverWrite"; 94 public static final String IGNORE_NO_WEB_SERVICE_FOUND_WARNING = "ignoreNoWebServiceFoundWarning"; 95 public static final String VERBOSE = "verbose"; 96 97 private WsgenOptions options; 98 protected AnnotationProcessorContext context; 99 private File sourceDir; 100 private boolean doNotOverWrite; 101 private boolean ignoreNoWebServiceFoundWarning = false; 102 private TypeMirror exceptionElement; 103 private TypeMirror runtimeExceptionElement; 104 private TypeElement defHolderElement; 105 private boolean isCommandLineInvocation; 106 private PrintStream out; 107 private Collection<TypeElement> processedTypeElements = new HashSet<TypeElement>(); 108 109 public WebServiceAp() { 110 this.context = new AnnotationProcessorContext(); 111 } 112 113 public WebServiceAp(WsgenOptions options, PrintStream out) { 114 this.options = options; 115 this.sourceDir = (options != null) ? options.sourceDir : null; 116 this.doNotOverWrite = (options != null) && options.doNotOverWrite; 117 this.context = new AnnotationProcessorContext(); 118 this.out = out; 119 } 120 121 @Override 122 public synchronized void init(ProcessingEnvironment processingEnv) { 123 super.init(processingEnv); 124 exceptionElement = processingEnv.getElementUtils().getTypeElement(Exception.class.getName()).asType(); 125 runtimeExceptionElement = processingEnv.getElementUtils().getTypeElement(RuntimeException.class.getName()).asType(); 126 defHolderElement = processingEnv.getElementUtils().getTypeElement(Holder.class.getName()); 127 if (options == null) { 128 options = new WsgenOptions(); 129 130 out = new PrintStream(new ByteArrayOutputStream()); 131 doNotOverWrite = getOption(DO_NOT_OVERWRITE); 132 ignoreNoWebServiceFoundWarning = getOption(IGNORE_NO_WEB_SERVICE_FOUND_WARNING); 133 options.verbose = getOption(VERBOSE); 134 isCommandLineInvocation = true; 135 } 136 options.filer = processingEnv.getFiler(); 137 } 138 139 private boolean getOption(String key) { 140 String value = processingEnv.getOptions().get(key); 141 if (value != null) { 142 return Boolean.valueOf(value); 143 } 144 return false; 145 } 146 147 @Override 148 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 149 if (context.getRound() != 1) { 150 return true; 151 } 152 context.incrementRound(); 153 WebService webService; 154 WebServiceProvider webServiceProvider; 155 WebServiceVisitor webServiceVisitor = new WebServiceWrapperGenerator(this, context); 156 boolean processedEndpoint = false; 157 Collection<TypeElement> classes = new ArrayList<TypeElement>(); 158 filterClasses(classes, roundEnv.getRootElements()); 159 for (TypeElement element : classes) { 160 webServiceProvider = element.getAnnotation(WebServiceProvider.class); 161 webService = element.getAnnotation(WebService.class); 162 if (webServiceProvider != null) { 163 if (webService != null) { 164 processError(WebserviceapMessages.WEBSERVICEAP_WEBSERVICE_AND_WEBSERVICEPROVIDER(element.getQualifiedName())); 165 } 166 processedEndpoint = true; 167 } 168 169 if (webService == null) { 170 continue; 171 } 172 173 element.accept(webServiceVisitor, null); 174 processedEndpoint = true; 175 } 176 if (!processedEndpoint) { 177 if (isCommandLineInvocation) { 178 if (!ignoreNoWebServiceFoundWarning) { 179 processWarning(WebserviceapMessages.WEBSERVICEAP_NO_WEBSERVICE_ENDPOINT_FOUND()); 180 } 181 } else { 182 processError(WebserviceapMessages.WEBSERVICEAP_NO_WEBSERVICE_ENDPOINT_FOUND()); 183 } 184 } 185 return true; 186 } 187 188 private void filterClasses(Collection<TypeElement> classes, Collection<? extends Element> elements) { 189 for (Element element : elements) { 190 if (element.getKind().equals(ElementKind.CLASS)) { 191 classes.add((TypeElement) element); 192 filterClasses(classes, ElementFilter.typesIn(element.getEnclosedElements())); 193 } 194 } 195 } 196 197 @Override 198 public void processWarning(String message) { 199 if (isCommandLineInvocation) { 200 processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, message); 201 } else { 202 report(message); 203 } 204 } 205 206 protected void report(String msg) { 207 if (out == null) { 208 if (LOGGER.isLoggable(Level.FINE)) { 209 LOGGER.log(Level.FINE, "No output set for web service annotation processor reporting."); 210 } 211 return; 212 } 213 out.println(msg); 214 out.flush(); 215 } 216 217 @Override 218 public void processError(String message) { 219 if (isCommandLineInvocation) { 220 processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, message); 221 throw new AbortException(); 222 } else { 223 throw new ModelerException(message); 224 } 225 } 226 227 @Override 228 public void processError(String message, Element element) { 229 if (isCommandLineInvocation) { 230 processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, message, element); 231 } else { 232 throw new ModelerException(message); 233 } 234 } 235 236 @Override 237 public boolean canOverWriteClass(String className) { 238 return !((doNotOverWrite && GeneratorUtil.classExists(options, className))); 239 } 240 241 @Override 242 public File getSourceDir() { 243 return sourceDir; 244 } 245 246 @Override 247 public boolean isRemote(TypeElement typeElement) { 248 return TypeModeler.isRemote(typeElement); 249 } 250 251 @Override 252 public boolean isServiceException(TypeMirror typeMirror) { 253 return processingEnv.getTypeUtils().isSubtype(typeMirror, exceptionElement) 254 && !processingEnv.getTypeUtils().isSubtype(typeMirror, runtimeExceptionElement) 255 && !TypeModeler.isRemoteException(processingEnv, typeMirror); 256 } 257 258 @Override 259 public TypeMirror getHolderValueType(TypeMirror type) { 260 return TypeModeler.getHolderValueType(type, defHolderElement, processingEnv); 261 } 262 263 @Override 264 public boolean checkAndSetProcessed(TypeElement typeElement) { 265 if (!processedTypeElements.contains(typeElement)) { 266 processedTypeElements.add(typeElement); 267 return false; 268 } 269 return true; 270 } 271 272 @Override 273 public void log(String message) { 274 if (options != null && options.verbose) { 275 message = new StringBuilder().append('[').append(message).append(']').toString(); // "[%s]" 276 processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message); 277 } 278 } 279 280 @Override 281 public WsgenOptions getOptions() { 282 return options; 283 } 284 285 @Override 286 public ProcessingEnvironment getProcessingEnvironment() { 287 return processingEnv; 288 } 289 290 @Override 291 public String getOperationName(Name messageName) { 292 return messageName != null ? messageName.toString() : null; 293 } 294 295 @Override 296 public SourceVersion getSupportedSourceVersion() { 297 return SourceVersion.latest(); 298 } 299} 300