001package ball.http.annotation.processing;
002/*-
003 * ##########################################################################
004 * Web API Client (HTTP) Utilities
005 * $Id: ProtocolJSR311AnnotationProcessor.java 5877 2020-05-04 22:00:56Z ball $
006 * $HeadURL: svn+ssh://svn.hcf.dev/var/spool/scm/repository.svn/ball-http/trunk/src/main/java/ball/http/annotation/processing/ProtocolJSR311AnnotationProcessor.java $
007 * %%
008 * Copyright (C) 2016 - 2020 Allen D. Ball
009 * %%
010 * Licensed under the Apache License, Version 2.0 (the "License");
011 * you may not use this file except in compliance with the License.
012 * You may obtain a copy of the License at
013 *
014 *      http://www.apache.org/licenses/LICENSE-2.0
015 *
016 * Unless required by applicable law or agreed to in writing, software
017 * distributed under the License is distributed on an "AS IS" BASIS,
018 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
019 * See the License for the specific language governing permissions and
020 * limitations under the License.
021 * ##########################################################################
022 */
023import ball.annotation.ServiceProviderFor;
024import ball.annotation.processing.AnnotatedProcessor;
025import ball.annotation.processing.For;
026import ball.http.annotation.Protocol;
027import java.lang.annotation.Annotation;
028import java.util.Set;
029import javax.annotation.processing.Processor;
030import javax.annotation.processing.RoundEnvironment;
031import javax.lang.model.element.AnnotationMirror;
032import javax.lang.model.element.AnnotationValue;
033import javax.lang.model.element.Element;
034import javax.lang.model.element.ExecutableElement;
035import javax.lang.model.element.TypeElement;
036import javax.ws.rs.DELETE;
037import javax.ws.rs.GET;
038import javax.ws.rs.HEAD;
039import javax.ws.rs.OPTIONS;
040import javax.ws.rs.PATCH;
041import javax.ws.rs.POST;
042import javax.ws.rs.PUT;
043import lombok.NoArgsConstructor;
044import lombok.ToString;
045
046import static java.util.stream.Collectors.toSet;
047import static javax.tools.Diagnostic.Kind.ERROR;
048import static lombok.AccessLevel.PROTECTED;
049
050/**
051 * Abstract base class for {@link javax.ws.rs JSR 311} {@link Annotation}
052 * {@link Processor} for {@link Protocol} interface methods.
053 *
054 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball}
055 * @version $Revision: 5877 $
056 */
057@NoArgsConstructor(access = PROTECTED)
058public abstract class ProtocolJSR311AnnotationProcessor
059                      extends AnnotatedProcessor {
060    @Override
061    public void process(RoundEnvironment roundEnv,
062                        TypeElement annotation, Element element) {
063        super.process(roundEnv, annotation, element);
064
065        switch (element.getKind()) {
066        case METHOD:
067            TypeElement type = (TypeElement) element.getEnclosingElement();
068
069            switch (type.getKind()) {
070            case INTERFACE:
071                if (type.getAnnotation(Protocol.class) != null) {
072                    check(annotation, type, (ExecutableElement) element);
073                }
074                break;
075
076            default:
077                break;
078            }
079            break;
080        }
081    }
082
083    /**
084     * Method to check an annotated interface method.
085     *
086     * @param   annotation      The annotation being processed.
087     * @param   type            The interface containing the method.
088     * @param   method          The annotated method.
089     */
090    protected abstract void check(TypeElement annotation,
091                                  TypeElement type, ExecutableElement method);
092
093    /**
094     * {@link javax.ws.rs JSR 311} method {@link Annotation}
095     * {@link Processor}.
096     */
097    @ServiceProviderFor({ Processor.class })
098    @For({
099            DELETE.class, GET.class, HEAD.class, OPTIONS.class,
100                PATCH.class, POST.class, PUT.class
101          })
102    @NoArgsConstructor @ToString
103    public static class Method extends ProtocolJSR311AnnotationProcessor {
104        @Override
105        protected void check(TypeElement annotation,
106                             TypeElement type, ExecutableElement method) {
107            Set<Class<? extends Annotation>> set =
108                getSupportedAnnotationTypeList().stream()
109                .filter(t -> method.getAnnotation(t) != null)
110                .collect(toSet());
111
112            switch (set.size()) {
113            case 0:
114                throw new IllegalStateException();
115                /*
116                 * break;
117                 */
118            case 1:
119                AnnotationMirror mirror =
120                    getAnnotationMirror(method, annotation);
121                AnnotationValue value = getAnnotationValue(mirror, "value");
122                break;
123
124            default:
125                print(ERROR, method,
126                      "%s may only be annotated with one of %s",
127                      method.getKind(),
128                      set.stream()
129                      .map(t -> "@" + t.getSimpleName())
130                      .collect(toSet()));
131                break;
132            }
133        }
134    }
135}