Home | History | Annotate | Download | only in checker
      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