blob: 18e4b964a56b8415201b78d3bf06408cd49df897 [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.databinding.tool.util;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.filefilter.TrueFileFilter;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.annotation.processing.ProcessingEnvironment;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
/**
* A utility class that helps adding build specific objects to the jar file
* and their extraction later on.
*/
public class GenerationalClassUtil {
private static List[] sCache = null;
public static <T extends Serializable> List<T> loadObjects(ExtensionFilter filter) {
if (sCache == null) {
buildCache();
}
//noinspection unchecked
return sCache[filter.ordinal()];
}
private static void buildCache() {
L.d("building generational class cache");
ClassLoader classLoader = GenerationalClassUtil.class.getClassLoader();
Preconditions.check(classLoader instanceof URLClassLoader, "Class loader must be an"
+ "instance of URLClassLoader. %s", classLoader);
//noinspection ConstantConditions
final URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
sCache = new List[ExtensionFilter.values().length];
for (ExtensionFilter filter : ExtensionFilter.values()) {
sCache[filter.ordinal()] = new ArrayList();
}
for (URL url : urlClassLoader.getURLs()) {
L.d("checking url %s for intermediate data", url);
try {
final File file = new File(url.toURI());
if (!file.exists()) {
L.d("cannot load file for %s", url);
continue;
}
if (file.isDirectory()) {
// probably exported classes dir.
loadFromDirectory(file);
} else {
// assume it is a zip file
loadFomZipFile(file);
}
} catch (IOException e) {
L.d("cannot open zip file from %s", url);
} catch (URISyntaxException e) {
L.d("cannot open zip file from %s", url);
}
}
}
private static void loadFromDirectory(File directory) {
for (File file : FileUtils.listFiles(directory, TrueFileFilter.INSTANCE,
TrueFileFilter.INSTANCE)) {
for (ExtensionFilter filter : ExtensionFilter.values()) {
if (filter.accept(file.getName())) {
InputStream inputStream = null;
try {
inputStream = FileUtils.openInputStream(file);
Serializable item = fromInputStream(inputStream);
if (item != null) {
//noinspection unchecked
sCache[filter.ordinal()].add(item);
L.d("loaded item %s from file", item);
}
} catch (IOException e) {
L.e(e, "Could not merge in Bindables from %s", file.getAbsolutePath());
} catch (ClassNotFoundException e) {
L.e(e, "Could not read Binding properties intermediate file. %s",
file.getAbsolutePath());
} finally {
IOUtils.closeQuietly(inputStream);
}
}
}
}
}
private static void loadFomZipFile(File file)
throws IOException {
ZipFile zipFile = new ZipFile(file);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
for (ExtensionFilter filter : ExtensionFilter.values()) {
if (!filter.accept(entry.getName())) {
continue;
}
InputStream inputStream = null;
try {
inputStream = zipFile.getInputStream(entry);
Serializable item = fromInputStream(inputStream);
L.d("loaded item %s from zip file", item);
if (item != null) {
//noinspection unchecked
sCache[filter.ordinal()].add(item);
}
} catch (IOException e) {
L.e(e, "Could not merge in Bindables from %s", file.getAbsolutePath());
} catch (ClassNotFoundException e) {
L.e(e, "Could not read Binding properties intermediate file. %s",
file.getAbsolutePath());
} finally {
IOUtils.closeQuietly(inputStream);
}
}
}
}
private static Serializable fromInputStream(InputStream inputStream)
throws IOException, ClassNotFoundException {
ObjectInputStream in = new ObjectInputStream(inputStream);
return (Serializable) in.readObject();
}
public static void writeIntermediateFile(ProcessingEnvironment processingEnv,
String packageName, String fileName, Serializable object) {
ObjectOutputStream oos = null;
try {
FileObject intermediate = processingEnv.getFiler().createResource(
StandardLocation.CLASS_OUTPUT, packageName,
fileName);
OutputStream ios = intermediate.openOutputStream();
oos = new ObjectOutputStream(ios);
oos.writeObject(object);
oos.close();
L.d("wrote intermediate bindable file %s %s", packageName, fileName);
} catch (IOException e) {
L.e(e, "Could not write to intermediate file: %s", fileName);
} finally {
IOUtils.closeQuietly(oos);
}
}
public enum ExtensionFilter {
BR("-br.bin"),
LAYOUT("-layoutinfo.bin"),
SETTER_STORE("-setter_store.bin");
private final String mExtension;
ExtensionFilter(String extension) {
mExtension = extension;
}
public boolean accept(String entryName) {
return entryName.endsWith(mExtension);
}
public String getExtension() {
return mExtension;
}
}
}