1a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar/*
2a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * Copyright (C) 2015 The Android Open Source Project
3a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar *
4a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * you may not use this file except in compliance with the License.
6a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * You may obtain a copy of the License at
7a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar *
8a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar *
10a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * Unless required by applicable law or agreed to in writing, software
11a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * See the License for the specific language governing permissions and
14a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * limitations under the License.
15a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar */
16a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
17fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding.annotationprocessor;
18a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
19fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.BindingBuildInfo;
204df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyarimport android.databinding.tool.CompilerChef;
21731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyarimport android.databinding.tool.processing.Scope;
22fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelAnalyzer;
234df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyarimport android.databinding.tool.util.Preconditions;
24fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.writer.AnnotationJavaFileWriter;
254df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyarimport android.databinding.tool.writer.BRWriter;
26fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.writer.JavaFileWriter;
27a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
28a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.util.Arrays;
29a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.util.List;
30a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.util.Set;
31a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
32a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport javax.annotation.processing.AbstractProcessor;
33a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport javax.annotation.processing.ProcessingEnvironment;
34a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport javax.annotation.processing.RoundEnvironment;
35a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport javax.annotation.processing.SupportedAnnotationTypes;
36a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport javax.annotation.processing.SupportedSourceVersion;
37a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport javax.lang.model.SourceVersion;
38a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport javax.lang.model.element.TypeElement;
39a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
40a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar@SupportedAnnotationTypes({
41fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount        "android.databinding.BindingAdapter",
42fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount        "android.databinding.Untaggable",
43fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount        "android.databinding.BindingMethods",
44fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount        "android.databinding.BindingConversion",
45fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount        "android.databinding.BindingBuildInfo"}
46a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar)
47a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar@SupportedSourceVersion(SourceVersion.RELEASE_7)
48a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar/**
49a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * Parent annotation processor that dispatches sub steps to ensure execution order.
50a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * Use initProcessingSteps to add a new step.
51a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar */
52a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarpublic class ProcessDataBinding extends AbstractProcessor {
53a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    private List<ProcessingStep> mProcessingSteps;
54a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    @Override
55a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
56a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        if (mProcessingSteps == null) {
57a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            initProcessingSteps();
58a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        }
59a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        final BindingBuildInfo buildInfo = BuildInfoUtil.load(roundEnv);
60a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        if (buildInfo == null) {
61a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            return false;
62a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        }
63a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        boolean done = true;
64a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        for (ProcessingStep step : mProcessingSteps) {
65a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            done = step.runStep(roundEnv, processingEnv, buildInfo) && done;
66a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        }
67a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        if (roundEnv.processingOver()) {
68a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            for (ProcessingStep step : mProcessingSteps) {
69a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                step.onProcessingOver(roundEnv, processingEnv, buildInfo);
70a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            }
71a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        }
72731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar        Scope.assertNoError();
73a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        return done;
74a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
75a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
76a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    private void initProcessingSteps() {
774df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar        final ProcessBindable processBindable = new ProcessBindable();
78a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        mProcessingSteps = Arrays.asList(
79a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                new ProcessMethodAdapters(),
804df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar                new ProcessExpressions(),
8161630faa88ee4817834d47294a0e17f19d8e1c51George Mount                processBindable
82a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        );
834df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar        Callback dataBinderWriterCallback = new Callback() {
844df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar            CompilerChef mChef;
854df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar            BRWriter mBRWriter;
864df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar            boolean mLibraryProject;
874df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar            int mMinSdk;
884df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar
894df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar            @Override
904df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar            public void onChefReady(CompilerChef chef, boolean libraryProject, int minSdk) {
914df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar                Preconditions.checkNull(mChef, "Cannot set compiler chef twice");
924df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar                chef.addBRVariables(processBindable);
934df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar                mChef = chef;
944df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar                mLibraryProject = libraryProject;
954df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar                mMinSdk = minSdk;
964df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar                considerWritingMapper();
974df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar            }
984df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar
994df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar            private void considerWritingMapper() {
1004df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar                if (mLibraryProject || mChef == null || mBRWriter == null) {
1014df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar                    return;
1024df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar                }
1034df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar                mChef.writeDataBinderMapper(mMinSdk, mBRWriter);
1044df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar            }
1054df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar
1064df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar            @Override
1074df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar            public void onBrWriterReady(BRWriter brWriter) {
1084df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar                Preconditions.checkNull(mBRWriter, "Cannot set br writer twice");
1094df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar                mBRWriter = brWriter;
1104df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar                considerWritingMapper();
1114df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar            }
1124df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar        };
113a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        AnnotationJavaFileWriter javaFileWriter = new AnnotationJavaFileWriter(processingEnv);
114a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        for (ProcessingStep step : mProcessingSteps) {
115a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            step.mJavaFileWriter = javaFileWriter;
1164df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar            step.mCallback = dataBinderWriterCallback;
117a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        }
118a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
119a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
120a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    @Override
121a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    public synchronized void init(ProcessingEnvironment processingEnv) {
122a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        super.init(processingEnv);
123a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        ModelAnalyzer.setProcessingEnvironment(processingEnv);
124a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
125a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
126a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    /**
127a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar     * To ensure execution order and binding build information, we use processing steps.
128a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar     */
129a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    public abstract static class ProcessingStep {
130a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        private boolean mDone;
131a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        private JavaFileWriter mJavaFileWriter;
1324df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar        protected Callback mCallback;
133a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
134a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        protected JavaFileWriter getWriter() {
135a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            return mJavaFileWriter;
136a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        }
137a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
138a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        private boolean runStep(RoundEnvironment roundEnvironment,
139a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                ProcessingEnvironment processingEnvironment,
140a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                BindingBuildInfo buildInfo) {
141a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            if (mDone) {
142a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                return true;
143a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            }
144a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            mDone = onHandleStep(roundEnvironment, processingEnvironment, buildInfo);
145a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            return mDone;
146a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        }
147a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
148a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        /**
149a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar         * Invoked in each annotation processing step.
150a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar         *
151a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar         * @return True if it is done and should never be invoked again.
152a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar         */
153a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        abstract public boolean onHandleStep(RoundEnvironment roundEnvironment,
154a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                ProcessingEnvironment processingEnvironment,
155a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                BindingBuildInfo buildInfo);
156a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
157a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        /**
158a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar         * Invoked when processing is done. A good place to generate the output if the
159a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar         * processor requires multiple steps.
160a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar         */
161a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        abstract public void onProcessingOver(RoundEnvironment roundEnvironment,
162a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                ProcessingEnvironment processingEnvironment,
163a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                BindingBuildInfo buildInfo);
164a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
1654df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar
1664df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar    interface Callback {
1674df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar        void onChefReady(CompilerChef chef, boolean libraryProject, int minSdk);
1684df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar        void onBrWriterReady(BRWriter brWriter);
1694df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar    }
170a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar}
171