• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
DataBinder(ResourceBundle resourceBundle)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     }
getLayoutBinders()59     public List<LayoutBinder> getLayoutBinders() {
60         return mLayoutBinders;
61     }
62 
sealModels()63     public void sealModels() {
64         for (LayoutBinder layoutBinder : mLayoutBinders) {
65             layoutBinder.sealModel();
66         }
67     }
68 
writerBaseClasses(boolean isLibrary)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 
writeBinders(int minSdk)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 
writeCallbackWrappers(int minSdk)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 
makeUnique(Set<String> existing, String wanted)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 
writeComponent()157     public void writeComponent() {
158         ComponentWriter componentWriter = new ComponentWriter();
159 
160         mWrittenClasses.add(COMPONENT_CLASS);
161         mFileWriter.writeToFile(COMPONENT_CLASS, componentWriter.createComponent());
162     }
163 
getWrittenClassNames()164     public Set<String> getWrittenClassNames() {
165         return mWrittenClasses;
166     }
167 
setFileWriter(JavaFileWriter fileWriter)168     public void setFileWriter(JavaFileWriter fileWriter) {
169         mFileWriter = fileWriter;
170     }
171 
getFileWriter()172     public JavaFileWriter getFileWriter() {
173         return mFileWriter;
174     }
175 }
176