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 android.databinding.tool.processing.Scope;
     20 import android.databinding.tool.processing.ScopedException;
     21 import android.databinding.tool.store.ResourceBundle;
     22 import android.databinding.tool.util.L;
     23 import android.databinding.tool.util.StringUtils;
     24 import android.databinding.tool.writer.CallbackWrapperWriter;
     25 import android.databinding.tool.writer.ComponentWriter;
     26 import android.databinding.tool.writer.JavaFileWriter;
     27 
     28 import java.util.ArrayList;
     29 import java.util.HashMap;
     30 import java.util.HashSet;
     31 import java.util.List;
     32 import java.util.Map;
     33 import java.util.Set;
     34 
     35 /**
     36  * The main class that handles parsing files and generating classes.
     37  */
     38 public class DataBinder {
     39     List<LayoutBinder> mLayoutBinders = new ArrayList<LayoutBinder>();
     40     private static final String COMPONENT_CLASS = "android.databinding.DataBindingComponent";
     41 
     42     private JavaFileWriter mFileWriter;
     43 
     44     Set<String> mWrittenClasses = new HashSet<String>();
     45 
     46     public DataBinder(ResourceBundle resourceBundle) {
     47         L.d("reading resource bundle into data binder");
     48         for (Map.Entry<String, List<ResourceBundle.LayoutFileBundle>> entry :
     49                 resourceBundle.getLayoutBundles().entrySet()) {
     50             for (ResourceBundle.LayoutFileBundle bundle : entry.getValue()) {
     51                 try {
     52                     mLayoutBinders.add(new LayoutBinder(bundle));
     53                 } catch (ScopedException ex) {
     54                     Scope.defer(ex);
     55                 }
     56             }
     57         }
     58     }
     59     public List<LayoutBinder> getLayoutBinders() {
     60         return mLayoutBinders;
     61     }
     62 
     63     public void sealModels() {
     64         for (LayoutBinder layoutBinder : mLayoutBinders) {
     65             layoutBinder.sealModel();
     66         }
     67     }
     68 
     69     public void writerBaseClasses(boolean isLibrary) {
     70         for (LayoutBinder layoutBinder : mLayoutBinders) {
     71             try {
     72                 Scope.enter(layoutBinder);
     73                 if (isLibrary || layoutBinder.hasVariations()) {
     74                     String className = layoutBinder.getClassName();
     75                     String canonicalName = layoutBinder.getPackage() + "." + className;
     76                     if (mWrittenClasses.contains(canonicalName)) {
     77                         continue;
     78                     }
     79                     L.d("writing data binder base %s", canonicalName);
     80                     mFileWriter.writeToFile(canonicalName,
     81                             layoutBinder.writeViewBinderBaseClass(isLibrary));
     82                     mWrittenClasses.add(canonicalName);
     83                 }
     84             } catch (ScopedException ex){
     85                 Scope.defer(ex);
     86             } finally {
     87                 Scope.exit();
     88             }
     89         }
     90     }
     91 
     92     public void writeBinders(int minSdk) {
     93         writeCallbackWrappers(minSdk);
     94         for (LayoutBinder layoutBinder : mLayoutBinders) {
     95             try {
     96                 Scope.enter(layoutBinder);
     97                 String className = layoutBinder.getImplementationName();
     98                 String canonicalName = layoutBinder.getPackage() + "." + className;
     99                 L.d("writing data binder %s", canonicalName);
    100                 mWrittenClasses.add(canonicalName);
    101                 mFileWriter.writeToFile(canonicalName, layoutBinder.writeViewBinder(minSdk));
    102             } catch (ScopedException ex) {
    103                 Scope.defer(ex);
    104             } finally {
    105                 Scope.exit();
    106             }
    107         }
    108     }
    109 
    110     private void writeCallbackWrappers(int minSdk) {
    111         Map<String, CallbackWrapper> uniqueWrappers = new HashMap<String, CallbackWrapper>();
    112         Set<String> classNames = new HashSet<String>();
    113         int callbackCounter = 0;
    114         for (LayoutBinder binder : mLayoutBinders) {
    115             for (Map.Entry<String, CallbackWrapper> entry : binder.getModel().getCallbackWrappers()
    116                     .entrySet()) {
    117                 final CallbackWrapper existing = uniqueWrappers.get(entry.getKey());
    118                 if (existing == null) {
    119                     // first time seeing this. register
    120                     final CallbackWrapper wrapper = entry.getValue();
    121                     uniqueWrappers.put(entry.getKey(), wrapper);
    122                     String listenerName = makeUnique(classNames, wrapper.klass.getSimpleName());
    123                     String methodName = makeUnique(classNames,
    124                             "_internalCallback" + StringUtils.capitalize(wrapper.method.getName()));
    125                     wrapper.prepare(listenerName, methodName);
    126                 } else {
    127                     // fill from previous
    128                     entry.getValue()
    129                             .prepare(existing.getClassName(), existing.getListenerMethodName());
    130                 }
    131 
    132             }
    133         }
    134 
    135         // now write the original wrappers
    136         for (CallbackWrapper wrapper : uniqueWrappers.values()) {
    137             final String code = new CallbackWrapperWriter(wrapper).write();
    138             String className = wrapper.getClassName();
    139             String canonicalName = wrapper.getPackage() + "." + className;
    140             mFileWriter.writeToFile(canonicalName, code);
    141             // these will be deleted for library projects.
    142             mWrittenClasses.add(canonicalName);
    143         }
    144 
    145     }
    146 
    147     private String makeUnique(Set<String> existing, String wanted) {
    148         int cnt = 1;
    149         while (existing.contains(wanted)) {
    150             wanted = wanted + cnt;
    151             cnt++;
    152         }
    153         existing.add(wanted);
    154         return wanted;
    155     }
    156 
    157     public void writeComponent() {
    158         ComponentWriter componentWriter = new ComponentWriter();
    159 
    160         mWrittenClasses.add(COMPONENT_CLASS);
    161         mFileWriter.writeToFile(COMPONENT_CLASS, componentWriter.createComponent());
    162     }
    163 
    164     public Set<String> getWrittenClassNames() {
    165         return mWrittenClasses;
    166     }
    167 
    168     public void setFileWriter(JavaFileWriter fileWriter) {
    169         mFileWriter = fileWriter;
    170     }
    171 
    172     public JavaFileWriter getFileWriter() {
    173         return mFileWriter;
    174     }
    175 }
    176