1 /* 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * - Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * - Neither the name of Oracle nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This source code is provided to illustrate the usage of a given feature 34 * or technique and has been deliberately simplified. Additional steps 35 * required for a production-quality application, such as security checks, 36 * input validation and proper error handling, might not be present in 37 * this sample code. 38 */ 39 package checker; 40 41 import javax.annotation.processing.ProcessingEnvironment; 42 import javax.annotation.processing.RoundEnvironment; 43 import javax.annotation.processing.SupportedAnnotationTypes; 44 import javax.annotation.processing.SupportedSourceVersion; 45 import javax.lang.model.SourceVersion; 46 import javax.lang.model.element.Element; 47 import javax.lang.model.element.TypeElement; 48 import javax.tools.Diagnostic; 49 import javax.xml.bind.JAXBContext; 50 import java.io.File; 51 import java.util.Arrays; 52 import java.util.HashSet; 53 import java.util.Set; 54 55 import javax.xml.bind.JAXBException; 56 57 /** 58 * Reads the device configuration from the XML file specified by -Adevice=device.xml. 59 * For each class in a project, checks required modules. If the device doesn't have 60 * the required module, then a compilation error will be shown. 61 */ 62 @SupportedAnnotationTypes("checker.RequireContainer") 63 @SupportedSourceVersion(SourceVersion.RELEASE_8) 64 public class PluginChecker extends javax.annotation.processing.AbstractProcessor { 65 66 /** 67 * Name of the option to get the path to the xml with device configuration. 68 */ 69 public static final String DEVICE_OPTION = "device"; 70 private Device device; 71 72 /** 73 * Only the device option is supported. 74 * 75 * {@inheritDoc} 76 */ 77 @Override 78 public Set<String> getSupportedOptions() { 79 return new HashSet<>(Arrays.asList(DEVICE_OPTION)); 80 } 81 82 /** 83 * Initializes the processor by loading the device configuration. 84 * 85 * {@inheritDoc} 86 */ 87 @Override 88 public synchronized void init(ProcessingEnvironment processingEnv) { 89 super.init(processingEnv); 90 try { 91 String deviceOption = processingEnv.getOptions().get(DEVICE_OPTION); 92 device = (Device) JAXBContext.newInstance(Device.class) 93 .createUnmarshaller().unmarshal(new File(deviceOption)); 94 } catch (JAXBException e) { 95 throw new RuntimeException( 96 "Please specify device by -Adevice=device.xml\n" 97 + e.toString(), e); 98 } 99 } 100 101 /** 102 * Processes @Require annotations and checks that Device meets requirements. 103 * 104 * {@inheritDoc} 105 */ 106 @Override 107 public boolean process(Set<? extends TypeElement> annotations, 108 RoundEnvironment roundEnv) { 109 for (Element el : roundEnv.getElementsAnnotatedWith(RequireContainer.class)) { 110 for (Require req : el.getAnnotationsByType(Require.class)) { 111 //for every Require annotation checks if device has module of required version. 112 Integer version = device.getSupportedModules().get(req.value()); 113 114 if (version == null 115 || version < req.minVersion() 116 || version > req.maxVersion()) { 117 //if module is optional then show only warning not error 118 if (req.optional()) { 119 processingEnv.getMessager() 120 .printMessage(Diagnostic.Kind.WARNING, 121 "Plugin [" + el + "] requires " + req 122 + "\n but device " + (version == null 123 ? "doesn't have such module." 124 + " This module is optional." 125 + " So plugin will work but miss" 126 + " some functionality" 127 : "has " + version 128 + " version of that module")); 129 } else { 130 processingEnv.getMessager() 131 .printMessage(Diagnostic.Kind.ERROR, 132 "Plugin [" + el + "] requires " + req 133 + "\n but device " 134 + (version == null 135 ? "doesn't have such module" 136 : "has " + version 137 + " version of that module")); 138 } 139 } 140 } 141 return true; 142 } 143 return false; 144 } 145 } 146