1a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar/* 2a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * Copyright (C) 2015 The Android Open Source Project 3a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * 4a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 5a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * you may not use this file except in compliance with the License. 6a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * You may obtain a copy of the License at 7a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * 8a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 9a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * 10a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * Unless required by applicable law or agreed to in writing, software 11a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 12a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * See the License for the specific language governing permissions and 14a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * limitations under the License. 15a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar */ 16a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 17fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding.tool.util; 18a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 19a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport org.apache.commons.io.FileUtils; 20a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport org.apache.commons.io.IOUtils; 21a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport org.apache.commons.io.filefilter.TrueFileFilter; 22a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 23a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.io.File; 24a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.io.IOException; 25a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.io.InputStream; 26a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.io.ObjectInputStream; 27a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.io.ObjectOutputStream; 28a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.io.OutputStream; 29a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.io.Serializable; 30a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.net.URISyntaxException; 31a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.net.URL; 32a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.net.URLClassLoader; 33a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.util.ArrayList; 34a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.util.Enumeration; 35a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.util.List; 36a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.util.zip.ZipEntry; 37a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.util.zip.ZipFile; 38a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 39a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport javax.annotation.processing.ProcessingEnvironment; 40a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport javax.tools.FileObject; 41a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport javax.tools.StandardLocation; 42a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 43a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar/** 44a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * A utility class that helps adding build specific objects to the jar file 45a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * and their extraction later on. 46a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar */ 47a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarpublic class GenerationalClassUtil { 48e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar private static List[] sCache = null; 49e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar public static <T extends Serializable> List<T> loadObjects(ExtensionFilter filter) { 50e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar if (sCache == null) { 51e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar buildCache(); 52a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 53e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar //noinspection unchecked 54e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar return sCache[filter.ordinal()]; 55e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar } 56e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar 57e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar private static void buildCache() { 58e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar L.d("building generational class cache"); 59e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar ClassLoader classLoader = GenerationalClassUtil.class.getClassLoader(); 60e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar Preconditions.check(classLoader instanceof URLClassLoader, "Class loader must be an" 61e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar + "instance of URLClassLoader. %s", classLoader); 62e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar //noinspection ConstantConditions 63a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar final URLClassLoader urlClassLoader = (URLClassLoader) classLoader; 64e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar sCache = new List[ExtensionFilter.values().length]; 65e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar for (ExtensionFilter filter : ExtensionFilter.values()) { 66e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar sCache[filter.ordinal()] = new ArrayList(); 67e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar } 68a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar for (URL url : urlClassLoader.getURLs()) { 69a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar L.d("checking url %s for intermediate data", url); 70a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar try { 71a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar final File file = new File(url.toURI()); 72a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar if (!file.exists()) { 73a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar L.d("cannot load file for %s", url); 74a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar continue; 75a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 76a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar if (file.isDirectory()) { 77a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar // probably exported classes dir. 78e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar loadFromDirectory(file); 79a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } else { 80a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar // assume it is a zip file 81e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar loadFomZipFile(file); 82a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 839784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar } catch (IOException e) { 849784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar L.d("cannot open zip file from %s", url); 859784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar } catch (URISyntaxException e) { 86a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar L.d("cannot open zip file from %s", url); 87a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 88a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 89a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 90a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 91e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar private static void loadFromDirectory(File directory) { 92e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar for (File file : FileUtils.listFiles(directory, TrueFileFilter.INSTANCE, 93e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar TrueFileFilter.INSTANCE)) { 94e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar for (ExtensionFilter filter : ExtensionFilter.values()) { 95e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar if (filter.accept(file.getName())) { 96e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar InputStream inputStream = null; 97e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar try { 98e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar inputStream = FileUtils.openInputStream(file); 99e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar Serializable item = fromInputStream(inputStream); 100e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar if (item != null) { 101e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar //noinspection unchecked 102e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar sCache[filter.ordinal()].add(item); 103e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar L.d("loaded item %s from file", item); 104e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar } 105e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar } catch (IOException e) { 106e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar L.e(e, "Could not merge in Bindables from %s", file.getAbsolutePath()); 107e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar } catch (ClassNotFoundException e) { 108e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar L.e(e, "Could not read Binding properties intermediate file. %s", 109e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar file.getAbsolutePath()); 110e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar } finally { 111e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar IOUtils.closeQuietly(inputStream); 112e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar } 113a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 114a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 115a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 116a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 117a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 118e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar private static void loadFomZipFile(File file) 119e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar throws IOException { 120a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar ZipFile zipFile = new ZipFile(file); 121a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar Enumeration<? extends ZipEntry> entries = zipFile.entries(); 122a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar while (entries.hasMoreElements()) { 123a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar ZipEntry entry = entries.nextElement(); 124e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar for (ExtensionFilter filter : ExtensionFilter.values()) { 125e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar if (!filter.accept(entry.getName())) { 126e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar continue; 127e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar } 128e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar InputStream inputStream = null; 129e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar try { 130e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar inputStream = zipFile.getInputStream(entry); 131e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar Serializable item = fromInputStream(inputStream); 132e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar L.d("loaded item %s from zip file", item); 133e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar if (item != null) { 134e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar //noinspection unchecked 135e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar sCache[filter.ordinal()].add(item); 136e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar } 137e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar } catch (IOException e) { 138e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar L.e(e, "Could not merge in Bindables from %s", file.getAbsolutePath()); 139e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar } catch (ClassNotFoundException e) { 140e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar L.e(e, "Could not read Binding properties intermediate file. %s", 141e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar file.getAbsolutePath()); 142e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar } finally { 143e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar IOUtils.closeQuietly(inputStream); 144a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 145a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 146a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 147a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 148a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 149e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar private static Serializable fromInputStream(InputStream inputStream) 150e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar throws IOException, ClassNotFoundException { 151a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar ObjectInputStream in = new ObjectInputStream(inputStream); 152e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar return (Serializable) in.readObject(); 153a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 154a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 155a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 156a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar public static void writeIntermediateFile(ProcessingEnvironment processingEnv, 157a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar String packageName, String fileName, Serializable object) { 158a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar ObjectOutputStream oos = null; 159a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar try { 160a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar FileObject intermediate = processingEnv.getFiler().createResource( 161a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar StandardLocation.CLASS_OUTPUT, packageName, 162a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar fileName); 163a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar OutputStream ios = intermediate.openOutputStream(); 164a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar oos = new ObjectOutputStream(ios); 165a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar oos.writeObject(object); 166a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar oos.close(); 167a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar L.d("wrote intermediate bindable file %s %s", packageName, fileName); 168a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } catch (IOException e) { 169a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar L.e(e, "Could not write to intermediate file: %s", fileName); 170a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } finally { 171a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar IOUtils.closeQuietly(oos); 172a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 173a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 174a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 175e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar public enum ExtensionFilter { 176e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar BR("-br.bin"), 177e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar LAYOUT("-layoutinfo.bin"), 178e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar SETTER_STORE("-setter_store.bin"); 179a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar private final String mExtension; 180e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar ExtensionFilter(String extension) { 181a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar mExtension = extension; 182a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 183a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 184a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar public boolean accept(String entryName) { 185a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar return entryName.endsWith(mExtension); 186a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 187e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar 188e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar public String getExtension() { 189e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar return mExtension; 190e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar } 191a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 192a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar} 193