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