blob: 216066cf33d9e240a655c208b61347b1adba49c7 [file] [log] [blame]
/*
* Copyright (C) 2014 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 com.android.jack.library;
import com.android.jack.library.v0003.InputJackLibraryImpl;
import com.android.jack.library.v0003.OutputJackLibraryImpl;
import com.android.sched.util.config.HasKeyId;
import com.android.sched.util.config.id.BooleanPropertyId;
import com.android.sched.util.config.id.MessageDigestPropertyId;
import com.android.sched.util.file.NoSuchFileException;
import com.android.sched.util.file.NotFileOrDirectoryException;
import com.android.sched.util.file.WrongPermissionException;
import com.android.sched.util.location.Location;
import com.android.sched.util.log.LoggerFactory;
import com.android.sched.vfs.GenericInputVFS;
import com.android.sched.vfs.InputVFS;
import com.android.sched.vfs.InputVFile;
import com.android.sched.vfs.VFS;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
/**
* Factory to instantiate {@link JackLibrary}.
*/
@HasKeyId
public abstract class JackLibraryFactory {
@Nonnull
public static final BooleanPropertyId GENERATE_JACKLIB_DIGEST = BooleanPropertyId.create(
"jack.library.digest", "Generate message digest in Jack library").addDefaultValue(
Boolean.TRUE).addCategory(DumpInLibrary.class);
@Nonnull
public static final MessageDigestPropertyId MESSAGE_DIGEST_ALGO = MessageDigestPropertyId
.create("jack.library.digest.algo", "Message digest algorithm use in Jack library")
.requiredIf(GENERATE_JACKLIB_DIGEST.getValue().isTrue()).addDefaultValue("SHA")
.addCategory(DumpInLibrary.class);
@Nonnull
private static Logger logger = LoggerFactory.getLogger();
@Nonnull
private static final String VERSION_FORMAT = "%04d";
@Nonnull
public static String getVersionString(@Nonnegative int version) {
return String.format(VERSION_FORMAT, Integer.valueOf(version));
}
@Nonnull
public static InputJackLibrary getInputLibrary(@Nonnull VFS vdir)
throws LibraryVersionException, LibraryFormatException, NotJackLibraryException {
GenericInputVFS giVFS = new GenericInputVFS(vdir);
Properties libraryProperties = loadLibraryProperties(giVFS);
String majorVersion = getVersionString(getMajorVersion(giVFS, libraryProperties));
InputJackLibrary inputJackLibrary = (InputJackLibrary) instantiateConstructorWithParameters(
vdir, "com.android.jack.library.v" + majorVersion + ".InputJackLibraryImpl",
new Class[] {VFS.class, Properties.class}, new Object[] {vdir, libraryProperties},
majorVersion);
return inputJackLibrary;
}
@Nonnull
public static OutputJackLibrary getOutputLibrary(@Nonnull VFS vfs,
@Nonnull String emitterId, @Nonnull String emitterVersion) {
return new OutputJackLibraryImpl(vfs, emitterId, emitterVersion);
}
private static int getMajorVersion(@Nonnull InputVFS vdir,
@Nonnull Properties libraryProperties) throws LibraryFormatException {
try {
return Integer.parseInt((String) libraryProperties.get(JackLibrary.KEY_LIB_MAJOR_VERSION));
} catch (NumberFormatException e) {
Location location = vdir.getLocation();
logger.log(Level.SEVERE, "Failed to parse the property " + JackLibrary.KEY_LIB_MAJOR_VERSION
+ " from the library " + location.getDescription(), e);
throw new LibraryFormatException(location);
}
}
@Nonnull
private static Properties loadLibraryProperties(@Nonnull InputVFS vfs)
throws NotJackLibraryException {
Properties libraryProperties = new Properties();
try {
InputVFile libProp =
vfs.getRootDir().getInputVFile(JackLibrary.LIBRARY_PROPERTIES_VPATH);
InputStream inputStream = null;
try {
inputStream = libProp.getInputStream();
libraryProperties.load(inputStream);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
logger.log(
Level.WARNING, "Failed to close ''{0}''", libProp.getLocation().getDescription());
}
}
}
} catch (IOException | NotFileOrDirectoryException | NoSuchFileException
| WrongPermissionException e) {
throw new NotJackLibraryException(vfs.getLocation());
}
return libraryProperties;
}
@Nonnull
private static Object instantiateConstructorWithParameters(@Nonnull VFS vdir,
@Nonnull String className, @Nonnull Class<?>[] parameterTypes,
@Nonnull Object[] parameterInstances, @Nonnull String version)
throws LibraryVersionException, LibraryFormatException {
Object constructorInstance = null;
try {
Class<?> libraryReaderClass = Class.forName(className);
Constructor<?> constructor = libraryReaderClass.getConstructor(parameterTypes);
constructorInstance = constructor.newInstance(parameterInstances);
} catch (SecurityException e) {
throw new AssertionError();
} catch (IllegalArgumentException e) {
throw new AssertionError("Illegal argument for library constructor for version " + version);
} catch (ClassNotFoundException e) {
throw new LibraryVersionException("Library " + vdir.getLocation().getDescription()
+ " has an unsupported version " + version);
} catch (NoSuchMethodException e) {
throw new AssertionError("Library constructor not found for version " + version);
} catch (InstantiationException e) {
throw new AssertionError("Problem instantiating a library for version " + version);
} catch (IllegalAccessException e) {
throw new AssertionError("Problem accessing library constructor for version " + version);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof LibraryFormatException) {
throw ((LibraryFormatException) cause);
} else if (cause instanceof LibraryVersionException) {
throw ((LibraryVersionException) cause);
} else if (cause instanceof RuntimeException) {
throw ((RuntimeException) cause);
} else if (cause instanceof Error) {
throw ((Error) cause);
}
throw new AssertionError(cause);
}
return constructorInstance;
}
@Nonnull
public static InputJackLibrary getInputLibrary(@Nonnull OutputJackLibrary jackOutputLibrary)
throws LibraryFormatException, LibraryVersionException, NotJackLibraryException {
GenericInputVFS giVFS = new GenericInputVFS(jackOutputLibrary.getVfs());
Properties libraryProperties = loadLibraryProperties(giVFS);
int majorVersion = getMajorVersion(giVFS, libraryProperties);
if (majorVersion != jackOutputLibrary.getMajorVersion()) {
throw new LibraryVersionException("Library "
+ jackOutputLibrary.getLocation().getDescription() + " does not have the latest version ("
+ majorVersion + ") and cannot be used as input/output");
}
return new InputJackLibraryImpl((OutputJackLibraryImpl) jackOutputLibrary, libraryProperties);
}
}