LayoutBinder.java revision 793e979f25e190162eacf46d6a4efc3efc1d2f91
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.WriterPackage;
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 = WriterPackage.getFieldName(first);
48            final String fieldName2 = WriterPackage.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            for (ResourceBundle.NameTypeLocation variable : mBundle.getVariables()) {
176                addVariable(variable.name, variable.type, variable.location);
177            }
178
179            for (ResourceBundle.NameTypeLocation userImport : mBundle.getImports()) {
180                mExprModel.addImport(userImport.name, userImport.type, userImport.location);
181            }
182            for (String javaLangClass : sJavaLangClasses) {
183                mExprModel.addImport(javaLangClass, "java.lang." + javaLangClass, null);
184            }
185            for (BindingTargetBundle targetBundle : mBundle.getBindingTargetBundles()) {
186                try {
187                    Scope.enter(targetBundle);
188                    final BindingTarget bindingTarget = createBindingTarget(targetBundle);
189                    for (BindingTargetBundle.BindingBundle bindingBundle : targetBundle
190                            .getBindingBundleList()) {
191                        bindingTarget.addBinding(bindingBundle.getName(),
192                                parse(bindingBundle.getExpr(), bindingBundle.getValueLocation()));
193                    }
194                    bindingTarget.resolveMultiSetters();
195                } finally {
196                    Scope.exit();
197                }
198            }
199            mSortedBindingTargets = new ArrayList<BindingTarget>(mBindingTargets);
200            Collections.sort(mSortedBindingTargets, COMPARE_FIELD_NAME);
201        } finally {
202            Scope.exit();
203        }
204    }
205
206    public void resolveWhichExpressionsAreUsed() {
207        List<Expr> used = new ArrayList<Expr>();
208        for (BindingTarget target : mBindingTargets) {
209            for (Binding binding : target.getBindings()) {
210                binding.getExpr().setIsUsed(true);
211                used.add(binding.getExpr());
212            }
213        }
214        while (!used.isEmpty()) {
215            Expr e = used.remove(used.size() - 1);
216            for (Dependency dep : e.getDependencies()) {
217                if (!dep.getOther().isUsed()) {
218                    used.add(dep.getOther());
219                    dep.getOther().setIsUsed(true);
220                }
221            }
222        }
223    }
224
225    public IdentifierExpr addVariable(String name, String type, Location location) {
226        Preconditions.check(!mUserDefinedVariables.containsKey(name),
227                "%s has already been defined as %s", name, type);
228        final IdentifierExpr id = mExprModel.identifier(name);
229        id.setUserDefinedType(type);
230        id.enableDirectInvalidation();
231        if (location != null) {
232            id.addLocation(location);
233        }
234        mUserDefinedVariables.put(name, type);
235        return id;
236    }
237
238    public HashMap<String, String> getUserDefinedVariables() {
239        return mUserDefinedVariables;
240    }
241
242    public BindingTarget createBindingTarget(ResourceBundle.BindingTargetBundle targetBundle) {
243        final BindingTarget target = new BindingTarget(targetBundle);
244        mBindingTargets.add(target);
245        target.setModel(mExprModel);
246        return target;
247    }
248
249    public Expr parse(String input, @Nullable Location locationInFile) {
250        final Expr parsed = mExpressionParser.parse(input, locationInFile);
251        parsed.setBindingExpression(true);
252        return parsed;
253    }
254
255    public List<BindingTarget> getBindingTargets() {
256        return mBindingTargets;
257    }
258
259    public List<BindingTarget> getSortedTargets() {
260        return mSortedBindingTargets;
261    }
262
263    public boolean isEmpty() {
264        return mExprModel.size() == 0;
265    }
266
267    public ExprModel getModel() {
268        return mExprModel;
269    }
270
271    private void ensureWriter() {
272        if (mWriter == null) {
273            mWriter = new LayoutBinderWriter(this);
274        }
275    }
276
277    public void sealModel() {
278        mExprModel.seal();
279    }
280
281    public String writeViewBinderBaseClass(boolean forLibrary) {
282        ensureWriter();
283        return mWriter.writeBaseClass(forLibrary);
284    }
285
286    public String writeViewBinder(int minSdk) {
287        ensureWriter();
288        Preconditions.checkNotNull(getPackage(), "package cannot be null");
289        Preconditions.checkNotNull(getClassName(), "base class name cannot be null");
290        return mWriter.write(minSdk);
291    }
292
293    public String getPackage() {
294        return mBundle.getBindingClassPackage();
295    }
296
297    public boolean isMerge() {
298        return mBundle.isMerge();
299    }
300
301    public String getModulePackage() {
302        return mModulePackage;
303    }
304
305    public String getLayoutname() {
306        return mBundle.getFileName();
307    }
308
309    public String getImplementationName() {
310        if (hasVariations()) {
311            return mBundle.getBindingClassName() + mBundle.getConfigName() + "Impl";
312        } else {
313            return mBundle.getBindingClassName();
314        }
315    }
316
317    public String getClassName() {
318        return mBundle.getBindingClassName();
319    }
320
321    public String getTag() {
322        return mBundle.getDirectory() + "/" + mBundle.getFileName();
323    }
324
325    public boolean hasVariations() {
326        return mBundle.hasVariations();
327    }
328
329    @Override
330    public String provideScopeFilePath() {
331        return mBundle.getAbsoluteFilePath();
332    }
333}
334