LayoutBinder.java revision 59229481aec5a284d322a2ca80dff836485feb0c
1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.databinding.tool;
18
19import org.antlr.v4.runtime.misc.Nullable;
20
21import android.databinding.tool.expr.Dependency;
22import android.databinding.tool.expr.Expr;
23import android.databinding.tool.expr.ExprModel;
24import android.databinding.tool.expr.IdentifierExpr;
25import android.databinding.tool.processing.Scope;
26import android.databinding.tool.processing.scopes.FileScopeProvider;
27import android.databinding.tool.store.Location;
28import android.databinding.tool.store.ResourceBundle;
29import android.databinding.tool.store.ResourceBundle.BindingTargetBundle;
30import android.databinding.tool.util.Preconditions;
31import android.databinding.tool.writer.LayoutBinderWriter;
32import android.databinding.tool.writer.LayoutBinderWriterKt;
33
34import java.util.ArrayList;
35import java.util.Collections;
36import java.util.Comparator;
37import java.util.HashMap;
38import java.util.List;
39
40/**
41 * Keeps all information about the bindings per layout file
42 */
43public class LayoutBinder implements FileScopeProvider {
44    private static final Comparator<BindingTarget> COMPARE_FIELD_NAME = new Comparator<BindingTarget>() {
45        @Override
46        public int compare(BindingTarget first, BindingTarget second) {
47            final String fieldName1 = LayoutBinderWriterKt.getFieldName(first);
48            final String fieldName2 = LayoutBinderWriterKt.getFieldName(second);
49            return fieldName1.compareTo(fieldName2);
50        }
51    };
52
53    /*
54    * val pkg: String, val projectPackage: String, val baseClassName: String,
55        val layoutName:String, val lb: LayoutExprBinding*/
56    private final ExprModel mExprModel;
57    private final ExpressionParser mExpressionParser;
58    private final List<BindingTarget> mBindingTargets;
59    private final List<BindingTarget> mSortedBindingTargets;
60    private String mModulePackage;
61    private final HashMap<String, String> mUserDefinedVariables = new HashMap<String, String>();
62
63    private LayoutBinderWriter mWriter;
64    private ResourceBundle.LayoutFileBundle mBundle;
65    private static final String[] sJavaLangClasses = {
66            "Deprecated",
67            "Override",
68            "SafeVarargs",
69            "SuppressWarnings",
70            "Appendable",
71            "AutoCloseable",
72            "CharSequence",
73            "Cloneable",
74            "Comparable",
75            "Iterable",
76            "Readable",
77            "Runnable",
78            "Thread.UncaughtExceptionHandler",
79            "Boolean",
80            "Byte",
81            "Character",
82            "Character.Subset",
83            "Character.UnicodeBlock",
84            "Class",
85            "ClassLoader",
86            "Compiler",
87            "Double",
88            "Enum",
89            "Float",
90            "InheritableThreadLocal",
91            "Integer",
92            "Long",
93            "Math",
94            "Number",
95            "Object",
96            "Package",
97            "Process",
98            "ProcessBuilder",
99            "Runtime",
100            "RuntimePermission",
101            "SecurityManager",
102            "Short",
103            "StackTraceElement",
104            "StrictMath",
105            "String",
106            "StringBuffer",
107            "StringBuilder",
108            "System",
109            "Thread",
110            "ThreadGroup",
111            "ThreadLocal",
112            "Throwable",
113            "Void",
114            "Thread.State",
115            "ArithmeticException",
116            "ArrayIndexOutOfBoundsException",
117            "ArrayStoreException",
118            "ClassCastException",
119            "ClassNotFoundException",
120            "CloneNotSupportedException",
121            "EnumConstantNotPresentException",
122            "Exception",
123            "IllegalAccessException",
124            "IllegalArgumentException",
125            "IllegalMonitorStateException",
126            "IllegalStateException",
127            "IllegalThreadStateException",
128            "IndexOutOfBoundsException",
129            "InstantiationException",
130            "InterruptedException",
131            "NegativeArraySizeException",
132            "NoSuchFieldException",
133            "NoSuchMethodException",
134            "NullPointerException",
135            "NumberFormatException",
136            "ReflectiveOperationException",
137            "RuntimeException",
138            "SecurityException",
139            "StringIndexOutOfBoundsException",
140            "TypeNotPresentException",
141            "UnsupportedOperationException",
142            "AbstractMethodError",
143            "AssertionError",
144            "ClassCircularityError",
145            "ClassFormatError",
146            "Error",
147            "ExceptionInInitializerError",
148            "IllegalAccessError",
149            "IncompatibleClassChangeError",
150            "InstantiationError",
151            "InternalError",
152            "LinkageError",
153            "NoClassDefFoundError",
154            "NoSuchFieldError",
155            "NoSuchMethodError",
156            "OutOfMemoryError",
157            "StackOverflowError",
158            "ThreadDeath",
159            "UnknownError",
160            "UnsatisfiedLinkError",
161            "UnsupportedClassVersionError",
162            "VerifyError",
163            "VirtualMachineError",
164    };
165
166    public LayoutBinder(ResourceBundle.LayoutFileBundle layoutBundle) {
167        try {
168            Scope.enter(this);
169            mExprModel = new ExprModel();
170            mExpressionParser = new ExpressionParser(mExprModel);
171            mBindingTargets = new ArrayList<BindingTarget>();
172            mBundle = layoutBundle;
173            mModulePackage = layoutBundle.getModulePackage();
174            // copy over data.
175            boolean addContext = true;
176            for (ResourceBundle.VariableDeclaration variable : mBundle.getVariables()) {
177                addVariable(variable.name, variable.type, variable.location, variable.declared);
178                if ("context".equals(variable.name)) {
179                    addContext = false;
180                }
181            }
182
183            for (ResourceBundle.NameTypeLocation userImport : mBundle.getImports()) {
184                mExprModel.addImport(userImport.name, userImport.type, userImport.location);
185                if ("context".equals(userImport.name)) {
186                    addContext = false;
187                }
188            }
189            if (addContext) {
190                mExprModel.builtInVariable("context", "android.content.Context",
191                        "getRoot().getContext()");
192            }
193            for (String javaLangClass : sJavaLangClasses) {
194                mExprModel.addImport(javaLangClass, "java.lang." + javaLangClass, null);
195            }
196            for (BindingTargetBundle targetBundle : mBundle.getBindingTargetBundles()) {
197                try {
198                    Scope.enter(targetBundle);
199                    final BindingTarget bindingTarget = createBindingTarget(targetBundle);
200                    for (BindingTargetBundle.BindingBundle bindingBundle : targetBundle
201                            .getBindingBundleList()) {
202                        try {
203                            Scope.enter(bindingBundle.getValueLocation());
204                            bindingTarget.addBinding(bindingBundle.getName(),
205                                    parse(bindingBundle.getExpr(), bindingBundle.getValueLocation()));
206                        } finally {
207                            Scope.exit();
208                        }
209                    }
210                    bindingTarget.resolveMultiSetters();
211                    bindingTarget.resolveListeners();
212                } finally {
213                    Scope.exit();
214                }
215            }
216            mSortedBindingTargets = new ArrayList<BindingTarget>(mBindingTargets);
217            Collections.sort(mSortedBindingTargets, COMPARE_FIELD_NAME);
218        } finally {
219            Scope.exit();
220        }
221    }
222
223    public void resolveWhichExpressionsAreUsed() {
224        List<Expr> used = new ArrayList<Expr>();
225        for (BindingTarget target : mBindingTargets) {
226            for (Binding binding : target.getBindings()) {
227                binding.getExpr().setIsUsed(true);
228                used.add(binding.getExpr());
229            }
230        }
231        while (!used.isEmpty()) {
232            Expr e = used.remove(used.size() - 1);
233            for (Dependency dep : e.getDependencies()) {
234                if (!dep.getOther().isUsed()) {
235                    used.add(dep.getOther());
236                    dep.getOther().setIsUsed(true);
237                }
238            }
239        }
240    }
241
242    public IdentifierExpr addVariable(String name, String type, Location location,
243            boolean declared) {
244        Preconditions.check(!mUserDefinedVariables.containsKey(name),
245                "%s has already been defined as %s", name, type);
246        final IdentifierExpr id = mExprModel.identifier(name);
247        id.setUserDefinedType(type);
248        id.enableDirectInvalidation();
249        if (location != null) {
250            id.addLocation(location);
251        }
252        mUserDefinedVariables.put(name, type);
253        if (declared) {
254            id.setDeclared();
255        }
256        return id;
257    }
258
259    public HashMap<String, String> getUserDefinedVariables() {
260        return mUserDefinedVariables;
261    }
262
263    public BindingTarget createBindingTarget(ResourceBundle.BindingTargetBundle targetBundle) {
264        final BindingTarget target = new BindingTarget(targetBundle);
265        mBindingTargets.add(target);
266        target.setModel(mExprModel);
267        return target;
268    }
269
270    public Expr parse(String input, @Nullable Location locationInFile) {
271        final Expr parsed = mExpressionParser.parse(input, locationInFile);
272        parsed.setBindingExpression(true);
273        return parsed;
274    }
275
276    public List<BindingTarget> getBindingTargets() {
277        return mBindingTargets;
278    }
279
280    public List<BindingTarget> getSortedTargets() {
281        return mSortedBindingTargets;
282    }
283
284    public boolean isEmpty() {
285        return mExprModel.size() == 0;
286    }
287
288    public ExprModel getModel() {
289        return mExprModel;
290    }
291
292    private void ensureWriter() {
293        if (mWriter == null) {
294            mWriter = new LayoutBinderWriter(this);
295        }
296    }
297
298    public void sealModel() {
299        mExprModel.seal();
300    }
301
302    public String writeViewBinderBaseClass(boolean forLibrary) {
303        ensureWriter();
304        return mWriter.writeBaseClass(forLibrary);
305    }
306
307    public String writeViewBinder(int minSdk) {
308        ensureWriter();
309        Preconditions.checkNotNull(getPackage(), "package cannot be null");
310        Preconditions.checkNotNull(getClassName(), "base class name cannot be null");
311        return mWriter.write(minSdk);
312    }
313
314    public String getPackage() {
315        return mBundle.getBindingClassPackage();
316    }
317
318    public boolean isMerge() {
319        return mBundle.isMerge();
320    }
321
322    public String getModulePackage() {
323        return mModulePackage;
324    }
325
326    public String getLayoutname() {
327        return mBundle.getFileName();
328    }
329
330    public String getImplementationName() {
331        if (hasVariations()) {
332            return mBundle.getBindingClassName() + mBundle.getConfigName() + "Impl";
333        } else {
334            return mBundle.getBindingClassName();
335        }
336    }
337
338    public String getClassName() {
339        return mBundle.getBindingClassName();
340    }
341
342    public String getTag() {
343        return mBundle.getDirectory() + "/" + mBundle.getFileName();
344    }
345
346    public boolean hasVariations() {
347        return mBundle.hasVariations();
348    }
349
350    @Override
351    public String provideScopeFilePath() {
352        return mBundle.getAbsoluteFilePath();
353    }
354}
355