197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar/* 297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * Copyright (C) 2015 The Android Open Source Project 397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * 497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * you may not use this file except in compliance with the License. 697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * You may obtain a copy of the License at 797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * 897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * 1097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * Unless required by applicable law or agreed to in writing, software 1197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 1297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * See the License for the specific language governing permissions and 1497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * limitations under the License. 1597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar */ 1697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 17fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding.annotationprocessor; 18e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mount 194ba16229a40e9758db86d4fb1df5119fdcb8aa2aDeepanshu Guptaimport com.google.common.base.Joiner; 204ba16229a40e9758db86d4fb1df5119fdcb8aa2aDeepanshu Gupta 21a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport org.apache.commons.io.FileUtils; 221b9940e612fc73202837fbe9db2f9035f307b5d1George Mountimport org.apache.commons.io.IOUtils; 231b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 24fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.BindingBuildInfo; 25fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.CompilerChef; 2628e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyarimport android.databinding.tool.LayoutXmlProcessor; 27fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.SdkUtil; 28fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.store.ResourceBundle; 29fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.util.GenerationalClassUtil; 30fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.util.L; 3128e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyarimport android.databinding.tool.util.Preconditions; 324ba16229a40e9758db86d4fb1df5119fdcb8aa2aDeepanshu Guptaimport android.databinding.tool.util.StringUtils; 331b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 3497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport java.io.File; 35a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.io.FilenameFilter; 36e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mountimport java.io.IOException; 37a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.io.InputStream; 38a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.io.Serializable; 3928e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyarimport java.util.ArrayList; 40a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.util.HashMap; 4128e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyarimport java.util.HashSet; 42a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.util.List; 43a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.util.Map; 44b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyarimport java.util.Set; 45e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mount 46a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport javax.annotation.processing.ProcessingEnvironment; 47e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mountimport javax.annotation.processing.RoundEnvironment; 488e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport javax.xml.bind.JAXBContext; 498e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport javax.xml.bind.JAXBException; 508e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport javax.xml.bind.Unmarshaller; 51e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mount 52a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarpublic class ProcessExpressions extends ProcessDataBinding.ProcessingStep { 534df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar public ProcessExpressions() { 5461630faa88ee4817834d47294a0e17f19d8e1c51George Mount } 5561630faa88ee4817834d47294a0e17f19d8e1c51George Mount 56a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar @Override 57a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar public boolean onHandleStep(RoundEnvironment roundEnvironment, 5828e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar ProcessingEnvironment processingEnvironment, BindingBuildInfo buildInfo) 5928e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar throws JAXBException { 60a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar ResourceBundle resourceBundle; 61a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar SdkUtil.initialize(buildInfo.minSdk(), new File(buildInfo.sdkRoot())); 62a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar resourceBundle = new ResourceBundle(buildInfo.modulePackage()); 6328e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar List<IntermediateV2> intermediateList = loadDependencyIntermediates(); 6428e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar for (Intermediate intermediate : intermediateList) { 6528e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar try { 6628e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar intermediate.appendTo(resourceBundle); 6728e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar } catch (Throwable throwable) { 6828e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar L.e(throwable, "unable to prepare resource bundle"); 6928e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar } 7028e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar } 7128e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar 7228e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar IntermediateV2 mine = createIntermediateFromLayouts(buildInfo.layoutInfoDir(), 7328e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar intermediateList); 74a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar if (mine != null) { 7528e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar mine.updateOverridden(resourceBundle); 76a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar intermediateList.add(mine); 77a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar saveIntermediate(processingEnvironment, buildInfo, mine); 7828e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar mine.appendTo(resourceBundle); 79a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 80a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar // generate them here so that bindable parser can read 81a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar try { 8228e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar writeResourceBundle(resourceBundle, buildInfo.isLibrary(), buildInfo.minSdk(), 8328e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar buildInfo.exportClassListTo()); 84a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } catch (Throwable t) { 85a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar L.e(t, "cannot generate view binders"); 86a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 87a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar return true; 88a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 89a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 9028e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar private List<IntermediateV2> loadDependencyIntermediates() { 911907fd71019ef16d4fc2953d56f1ec0702275aa0Yigit Boyar final List<Intermediate> original = GenerationalClassUtil.loadObjects( 9228e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar GenerationalClassUtil.ExtensionFilter.LAYOUT); 9328e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar final List<IntermediateV2> upgraded = new ArrayList<IntermediateV2>(original.size()); 9428e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar for (Intermediate intermediate : original) { 9528e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar final Intermediate updatedIntermediate = intermediate.upgrade(); 9628e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar Preconditions.check(updatedIntermediate instanceof IntermediateV2, "Incompatible data" 9728e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar + " binding dependency. Please update your dependencies or recompile them with" 9828e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar + " application module's data binding version."); 9928e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar //noinspection ConstantConditions 10028e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar upgraded.add((IntermediateV2) updatedIntermediate); 10128e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar } 10228e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar return upgraded; 10328e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar } 10428e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar 105a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar private void saveIntermediate(ProcessingEnvironment processingEnvironment, 10628e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar BindingBuildInfo buildInfo, IntermediateV2 intermediate) { 107a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar GenerationalClassUtil.writeIntermediateFile(processingEnvironment, 108e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar buildInfo.modulePackage(), buildInfo.modulePackage() + 109e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar GenerationalClassUtil.ExtensionFilter.LAYOUT.getExtension(), 110a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar intermediate); 111a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 112a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 113a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar @Override 114a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar public void onProcessingOver(RoundEnvironment roundEnvironment, 115a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar ProcessingEnvironment processingEnvironment, BindingBuildInfo buildInfo) { 116a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 117a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 11828e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar private IntermediateV2 createIntermediateFromLayouts(String layoutInfoFolderPath, 11928e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar List<IntermediateV2> intermediateList) { 12028e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar final Set<String> excludeList = new HashSet<String>(); 12128e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar for (IntermediateV2 lib : intermediateList) { 12228e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar excludeList.addAll(lib.mLayoutInfoMap.keySet()); 123a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 124a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar final File layoutInfoFolder = new File(layoutInfoFolderPath); 125a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar if (!layoutInfoFolder.isDirectory()) { 126a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar L.d("layout info folder does not exist, skipping for %s", layoutInfoFolderPath); 127a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar return null; 128a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 12928e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar IntermediateV2 result = new IntermediateV2(); 130a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar for (File layoutFile : layoutInfoFolder.listFiles(new FilenameFilter() { 131a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar @Override 132a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar public boolean accept(File dir, String name) { 13328e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar return name.endsWith(".xml") && !excludeList.contains(name); 13400da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 135a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar })) { 136a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar try { 137a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar result.addEntry(layoutFile.getName(), FileUtils.readFileToString(layoutFile)); 138a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } catch (IOException e) { 139a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar L.e(e, "cannot load layout file information. Try a clean build"); 1401b9940e612fc73202837fbe9db2f9035f307b5d1George Mount } 141a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 142a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar return result; 143a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 144a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 145e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount private void writeResourceBundle(ResourceBundle resourceBundle, boolean forLibraryModule, 1464df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar final int minSdk, String exportClassNamesTo) 147a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar throws JAXBException { 1484df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar final CompilerChef compilerChef = CompilerChef.createChef(resourceBundle, getWriter()); 149a649c6ce3f6eb4882221e77a1d27e0d28c4c13a0George Mount compilerChef.sealModels(); 150a649c6ce3f6eb4882221e77a1d27e0d28c4c13a0George Mount compilerChef.writeComponent(); 151a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar if (compilerChef.hasAnythingToGenerate()) { 152dea555cf42dc3583604699c8c018d22681f56166George Mount compilerChef.writeViewBinderInterfaces(forLibraryModule); 153a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar if (!forLibraryModule) { 15496e1c821dd446d1ed78f8ae61131550588f60a24George Mount compilerChef.writeViewBinders(minSdk); 1551b9940e612fc73202837fbe9db2f9035f307b5d1George Mount } 1561b9940e612fc73202837fbe9db2f9035f307b5d1George Mount } 157b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar if (forLibraryModule && exportClassNamesTo == null) { 158b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar L.e("When compiling a library module, build info must include exportClassListTo path"); 159b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar } 160b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar if (forLibraryModule) { 161b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar Set<String> classNames = compilerChef.getWrittenClassNames(); 1624ba16229a40e9758db86d4fb1df5119fdcb8aa2aDeepanshu Gupta String out = Joiner.on(StringUtils.LINE_SEPARATOR).join(classNames); 163b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar L.d("Writing list of classes to %s . \nList:%s", exportClassNamesTo, out); 164b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar try { 1654df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar //noinspection ConstantConditions 1664df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar FileUtils.write(new File(exportClassNamesTo), out); 167b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar } catch (IOException e) { 168b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar L.e(e, "Cannot create list of written classes"); 169b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar } 1701bbaf7cdf7f9d93ae09365192abb2288cf0dfb41George Mount } 1714df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar mCallback.onChefReady(compilerChef, forLibraryModule, minSdk); 172a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 173e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mount 17428e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar public interface Intermediate extends Serializable { 175a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 176a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar Intermediate upgrade(); 177a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 17828e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar void appendTo(ResourceBundle resourceBundle) throws Throwable; 1798e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount } 1808e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount 181a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar public static class IntermediateV1 implements Intermediate { 182a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 183a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar transient Unmarshaller mUnmarshaller; 184a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 185a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar // name to xml content map 186b1356339eaa6c8e967e4fc1dc283b82909a1208dYigit Boyar Map<String, String> mLayoutInfoMap = new HashMap<String, String>(); 187a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 188a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar @Override 189a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar public Intermediate upgrade() { 19028e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar final IntermediateV2 updated = new IntermediateV2(); 19128e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar updated.mLayoutInfoMap = mLayoutInfoMap; 19228e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar updated.mUnmarshaller = mUnmarshaller; 19328e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar return updated; 194a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 195a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 196a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar @Override 197a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar public void appendTo(ResourceBundle resourceBundle) throws JAXBException { 198a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar if (mUnmarshaller == null) { 199a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar JAXBContext context = JAXBContext 200a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar .newInstance(ResourceBundle.LayoutFileBundle.class); 201a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar mUnmarshaller = context.createUnmarshaller(); 2028e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount } 203a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar for (String content : mLayoutInfoMap.values()) { 204a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar final InputStream is = IOUtils.toInputStream(content); 205a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar try { 206a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar final ResourceBundle.LayoutFileBundle bundle 207a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar = (ResourceBundle.LayoutFileBundle) mUnmarshaller.unmarshal(is); 2080390898cf7c4fcad255e8cfd6802f722b516cb2cGeorge Mount resourceBundle.addLayoutBundle(bundle); 209a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar L.d("loaded layout info file %s", bundle); 210a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } finally { 211a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar IOUtils.closeQuietly(is); 2121b9940e612fc73202837fbe9db2f9035f307b5d1George Mount } 2131b9940e612fc73202837fbe9db2f9035f307b5d1George Mount } 214a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 2158e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount 216a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar public void addEntry(String name, String contents) { 217a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar mLayoutInfoMap.put(name, contents); 2181b9940e612fc73202837fbe9db2f9035f307b5d1George Mount } 2198e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount 22028e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar // keeping the method to match deserialized structure 22128e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar @SuppressWarnings("unused") 222a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar public void removeOverridden(List<Intermediate> existing) { 22328e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar } 22428e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar } 22528e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar 22628e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar public static class IntermediateV2 extends IntermediateV1 { 22728e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar // specify so that we can define updates ourselves. 22828e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar private static final long serialVersionUID = 2L; 22928e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar @Override 23028e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar public void appendTo(ResourceBundle resourceBundle) throws JAXBException { 23128e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar for (Map.Entry<String, String> entry : mLayoutInfoMap.entrySet()) { 23228e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar final InputStream is = IOUtils.toInputStream(entry.getValue()); 23328e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar try { 23428e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar final ResourceBundle.LayoutFileBundle bundle = ResourceBundle.LayoutFileBundle 23528e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar .fromXML(is); 23628e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar resourceBundle.addLayoutBundle(bundle); 23728e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar L.d("loaded layout info file %s", bundle); 23828e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar } finally { 23928e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar IOUtils.closeQuietly(is); 24028e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar } 24128e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar } 24228e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar } 24328e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar 24428e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar /** 24528e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar * if a layout is overridden from a module (which happens when layout is auto-generated), 24628e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar * we need to update its contents from the class that overrides it. 24728e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar * This must be done before this bundle is saved, otherwise, it will not be recognized 24828e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar * when it is used in another project. 24928e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar */ 25028e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar public void updateOverridden(ResourceBundle bundle) throws JAXBException { 25128e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar // When a layout is copied from inherited module, it is eleminated while reading 25228e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar // info files. (createIntermediateFromLayouts). 25328e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar // Build process may also duplicate some files at compile time. This is where 25428e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar // we detect those copies and force inherit their module and classname information. 25528e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar final HashMap<String, List<ResourceBundle.LayoutFileBundle>> bundles = bundle 25628e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar .getLayoutBundles(); 25728e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar for (Map.Entry<String, String> info : mLayoutInfoMap.entrySet()) { 25828e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar String key = LayoutXmlProcessor.exportLayoutNameFromInfoFileName(info.getKey()); 25928e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar final List<ResourceBundle.LayoutFileBundle> existingList = bundles.get(key); 26028e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar if (existingList != null && !existingList.isEmpty()) { 26128e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar ResourceBundle.LayoutFileBundle myBundle = ResourceBundle.LayoutFileBundle 26228e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar .fromXML(IOUtils.toInputStream(info.getValue())); 26328e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar final ResourceBundle.LayoutFileBundle inheritFrom = existingList.get(0); 26428e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar myBundle.inheritConfigurationFrom(inheritFrom); 26528e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar L.d("inheriting data for %s (%s) from %s", info.getKey(), key, inheritFrom); 26628e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar mLayoutInfoMap.put(info.getKey(), myBundle.toXML()); 267a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 268a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 26900da715547ee7d5d38a3b8576090ca427a94daa5George Mount } 270e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mount } 271e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mount} 272