下面列出了java.util.jar.JarFile#getEntry ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Gathers the {@link ManifestDigest} for {@code pkg} if it exists in the
* APK. If it successfully scanned the package and found the
* {@code AndroidManifest.xml}, {@code true} is returned.
*/
public boolean collectManifestDigest(Package pkg) {
try {
final JarFile jarFile = new JarFile(mArchiveSourcePath);
try {
final ZipEntry je = jarFile.getEntry(ANDROID_MANIFEST_FILENAME);
if (je != null) {
pkg.manifestDigest = ManifestDigest.fromInputStream(jarFile.getInputStream(je));
}
} finally {
jarFile.close();
}
return true;
} catch (IOException e) {
return false;
}
}
public Properties getProperties(String entryName) {
File defaultDirectoryFile = new File(Paths.getYalpPath(context), entryName);
if (defaultDirectoryFile.exists()) {
Log.i(getClass().getSimpleName(), "Loading device info from " + defaultDirectoryFile.getAbsolutePath());
return getProperties(defaultDirectoryFile);
} else {
Log.i(getClass().getSimpleName(), "Loading device info from " + getApkFile() + "/" + entryName);
JarFile jarFile = getApkAsJar();
if (null == jarFile || null == jarFile.getEntry(entryName)) {
Properties empty = new Properties();
empty.setProperty("Could not read ", entryName);
return empty;
}
return getProperties(jarFile, (JarEntry) jarFile.getEntry(entryName));
}
}
/**
* Returns true if the given .jar file exists and contains the entry.
*/
public static boolean containsEntry(File file, String entryPath) {
if (file.canRead()) {
try {
JarFile jarFile = new JarFile(file);
try {
return jarFile.getEntry(entryPath) != null;
}
finally {
jarFile.close();
}
}
catch (IOException ignored) { }
}
return false;
}
private static String findCurrVer(JarFile jar, String infix) throws IOException {
// first try to find the Bundle for 5.0+ (after openide split)
ZipEntry bundle = jar.getEntry("org/netbeans/core/startup/Bundle" + infix + ".properties"); // NOI18N
if (bundle == null) {
// might be <5.0 (before openide split)
bundle = jar.getEntry("org/netbeans/core/Bundle" + infix + ".properties"); // NOI18N
}
if (bundle == null) {
return null;
}
Properties props = new Properties();
InputStream is = jar.getInputStream(bundle);
try {
props.load(is);
} finally {
is.close();
}
return props.getProperty("currentVersion"); // NOI18N
}
private static String readManifestFromJar(String jarfile) throws IOException {
JarFile jar = new JarFile(jarfile);
ZipEntry manifestEntry = jar.getEntry("META-INF/MANIFEST.MF");
if (manifestEntry == null) {
throw new IllegalArgumentException("Jar does not contain a manifest at META-INF/MANIFEST.MF");
}
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(jar.getInputStream(manifestEntry), "UTF-8"));
String currentLine;
while ((currentLine = bufferedReader.readLine()) != null) {
// Ignore empty new lines
if (currentLine.trim().length() > 0) {
stringBuilder.append(currentLine + "\n");
}
}
return stringBuilder.toString();
}
/**
* Add a resources JAR. The contents of /META-INF/resources/ will be used if
* a requested resource can not be found in the main context.
*/
public void addResourcesJar(URL url) {
try {
JarURLConnection conn = (JarURLConnection) url.openConnection();
JarFile jarFile = conn.getJarFile();
ZipEntry entry = jarFile.getEntry("/");
WARDirContext warDirContext = new WARDirContext(jarFile,
new WARDirContext.Entry("/", entry));
warDirContext.loadEntries();
altDirContexts.add(warDirContext);
} catch (IOException ioe) {
log.warn(sm.getString("resources.addResourcesJarFail", url), ioe);
}
}
public static String readEntry(final JarFile jarFile, final String name, final Alerts alerts) {
final ZipEntry entry = jarFile.getEntry(name);
if (entry == null) {
return null;
}
try {
final String text = IO.slurp(jarFile.getInputStream(entry));
return text;
} catch (final Exception e) {
alerts.addError("Unable to read " + name + " from " + jarFile.getName());
return null;
}
}
private static void defineDependancies(byte[] bytes, JarFile jar, File jarFile, Stack<String> depStack) throws Exception
{
ClassReader reader = new ClassReader(bytes);
DependancyLister lister = new DependancyLister(Opcodes.ASM4);
reader.accept(lister, 0);
depStack.push(reader.getClassName());
for(String dependancy : lister.getDependancies())
{
if(depStack.contains(dependancy))
continue;
try
{
Launch.classLoader.loadClass(dependancy.replace('/', '.'));
}
catch(ClassNotFoundException cnfe)
{
ZipEntry entry = jar.getEntry(dependancy+".class");
if(entry == null)
throw new Exception("Dependency "+dependancy+" not found in jar file "+jarFile.getName());
byte[] depbytes = readFully(jar.getInputStream(entry));
defineDependancies(depbytes, jar, jarFile, depStack);
logger.debug("Defining dependancy: "+dependancy);
defineClass(dependancy.replace('/', '.'), depbytes);
}
}
depStack.pop();
}
private void processDownloadedIndex(File outputFile, String cacheTag)
throws IOException, IndexUpdater.UpdateException {
JarFile jarFile = new JarFile(outputFile, true);
JarEntry indexEntry = (JarEntry) jarFile.getEntry(DATA_FILE_NAME);
InputStream indexInputStream = new ProgressBufferedInputStream(jarFile.getInputStream(indexEntry),
processIndexListener, (int) indexEntry.getSize());
processIndexV1(indexInputStream, indexEntry, cacheTag);
jarFile.close();
}
private boolean upToDate(File outputFile, File inputFile, JarFile jar) {
if (outputFile.exists()) {
return inputFile.lastModified() < outputFile.lastModified();
} else if (isReplaceOutput()) {
return jar.getEntry(CLASSES_DEX) != null;
}
return false;
}
@Test(expected = IndexUpdater.SigningException.class)
public void testIndexV1WithWrongCert() throws IOException, IndexUpdater.UpdateException {
String badCert = "308202ed308201d5a003020102020426ffa009300d06092a864886f70d01010b05003027310b300906035504061302444531183016060355040a130f4e4f47415050532050726f6a656374301e170d3132313030363132303533325a170d3337303933303132303533325a3027310b300906035504061302444531183016060355040a130f4e4f47415050532050726f6a65637430820122300d06092a864886f70d01010105000382010f003082010a02820101009a8d2a5336b0eaaad89ce447828c7753b157459b79e3215dc962ca48f58c2cd7650df67d2dd7bda0880c682791f32b35c504e43e77b43c3e4e541f86e35a8293a54fb46e6b16af54d3a4eda458f1a7c8bc1b7479861ca7043337180e40079d9cdccb7e051ada9b6c88c9ec635541e2ebf0842521c3024c826f6fd6db6fd117c74e859d5af4db04448965ab5469b71ce719939a06ef30580f50febf96c474a7d265bb63f86a822ff7b643de6b76e966a18553c2858416cf3309dd24278374bdd82b4404ef6f7f122cec93859351fc6e5ea947e3ceb9d67374fe970e593e5cd05c905e1d24f5a5484f4aadef766e498adf64f7cf04bddd602ae8137b6eea40722d0203010001a321301f301d0603551d0e04160414110b7aa9ebc840b20399f69a431f4dba6ac42a64300d06092a864886f70d01010b0500038201010007c32ad893349cf86952fb5a49cfdc9b13f5e3c800aece77b2e7e0e9c83e34052f140f357ec7e6f4b432dc1ed542218a14835acd2df2deea7efd3fd5e8f1c34e1fb39ec6a427c6e6f4178b609b369040ac1f8844b789f3694dc640de06e44b247afed11637173f36f5886170fafd74954049858c6096308fc93c1bc4dd5685fa7a1f982a422f2a3b36baa8c9500474cf2af91c39cbec1bc898d10194d368aa5e91f1137ec115087c31962d8f76cd120d28c249cf76f4c70f5baa08c70a7234ce4123be080cee789477401965cfe537b924ef36747e8caca62dfefdd1a6288dcb1c4fd2aaa6131a7ad254e9742022cfd597d2ca5c660ce9e41ff537e5a4041e37"; // NOCHECKSTYLE LineLength
Repo repo = MultiIndexUpdaterTest.createRepo("Testy", TESTY_JAR, context, badCert);
IndexV1Updater updater = new IndexV1Updater(context, repo);
JarFile jarFile = new JarFile(TestUtils.copyResourceToTempFile(TESTY_JAR), true);
JarEntry indexEntry = (JarEntry) jarFile.getEntry(IndexV1Updater.DATA_FILE_NAME);
InputStream indexInputStream = jarFile.getInputStream(indexEntry);
updater.processIndexV1(indexInputStream, indexEntry, "fakeEtag");
fail(); // it should never reach here, it should throw a SigningException
getClass().getResourceAsStream("foo");
}
@Override
public void connect()
throws IOException {
if( !connected ) {
final String urlPath = url.getPath();
final Matcher matcher = URL_PATTERN.matcher( urlPath );
if( matcher.matches() ) {
final String path = matcher.group( 1 );
final String subPath = matcher.group( 2 );
final JarURLConnection jarURLConnection = (JarURLConnection) new URL( "jar:" + path ).openConnection();
inputStream = jarURLConnection.getInputStream();
if( subPath.isEmpty() == false ) {
JarFile jar = retrieve( new URL( path ), inputStream );
final String[] nodes = NESTING_SEPARATION_PATTERN.split( subPath );
int i;
final StringBuilder builder = new StringBuilder( path.length() + subPath.length() );
builder.append( path );
for( i = 0; i < nodes.length - 1; i++ ) {
builder.append( "!/" ).append( nodes[ i ] );
jar = retrieve( new URL( builder.toString() ), inputStream );
}
final ZipEntry entry = jar.getEntry( nodes[ i ] );
entrySize = entry.getSize();
inputStream = jar.getInputStream( entry );
}
} else {
throw new MalformedURLException( "Invalid JAP URL path: " + urlPath );
}
connected = true;
}
}
/**
* Add a resources JAR. The contents of /META-INF/resources/ will be used if
* a requested resource can not be found in the main context.
*/
public void addResourcesJar(URL url) {
try {
JarURLConnection conn = (JarURLConnection) url.openConnection();
JarFile jarFile = conn.getJarFile();
ZipEntry entry = jarFile.getEntry("/");
WARDirContext warDirContext = new WARDirContext(jarFile,
new WARDirContext.Entry("/", entry));
warDirContext.loadEntries();
altDirContexts.add(warDirContext);
} catch (IOException ioe) {
log.warn(sm.getString("resources.addResourcesJarFail", url), ioe);
}
}
public static void registerRepo(Context context, InputStream inputStream, Uri repoUri)
throws IOException, IndexUpdater.SigningException {
if (inputStream == null) {
return;
}
File destFile = File.createTempFile("dl-", IndexV1Updater.SIGNED_FILE_NAME, context.getCacheDir());
FileUtils.copyInputStreamToFile(inputStream, destFile);
JarFile jarFile = new JarFile(destFile, true);
JarEntry indexEntry = (JarEntry) jarFile.getEntry(IndexV1Updater.DATA_FILE_NAME);
IOUtils.readLines(jarFile.getInputStream(indexEntry));
Certificate certificate = IndexUpdater.getSigningCertFromJar(indexEntry);
String fingerprint = Utils.calcFingerprint(certificate);
Log.i(TAG, "Got fingerprint: " + fingerprint);
destFile.delete();
Log.i(TAG, "Found a valid, signed index-v1.json");
for (Repo repo : RepoProvider.Helper.all(context)) {
if (fingerprint.equals(repo.fingerprint)) {
Log.i(TAG, repo.address + " has the SAME fingerprint: " + fingerprint);
} else {
Log.i(TAG, repo.address + " different fingerprint");
}
}
AddRepoIntentService.addRepo(context, repoUri, fingerprint);
// TODO rework IndexUpdater.getSigningCertFromJar to work for here
}
private LoadedPlugin loadPlugin0(File file) throws Exception {
JsonElement modModulesElement = new JsonParser().parse(FileUtils.readFileToString(The5zigMod.getModuleMaster().getFile()));
JarFile jarFile = new JarFile(file);
ZipEntry pluginEntry = jarFile.getEntry("plugin.json");
if (pluginEntry == null) {
throw new PluginException("plugin.json not found!");
}
JsonElement jsonElement = parseJson(jarFile, pluginEntry);
if (!jsonElement.isJsonObject()) {
throw new PluginException("Invalid plugin.json in file " + jarFile.getName());
}
JsonObject jsonObject = jsonElement.getAsJsonObject();
if (!jsonObject.has("main") || !jsonObject.get("main").isJsonPrimitive()) {
throw new PluginException("main not found in plugin.json in file " + jarFile.getName());
}
String main = jsonObject.get("main").getAsString();
PluginClassLoader classLoader = new PluginClassLoader(this, this.getClass().getClassLoader(), file);
Class mainClass = classLoader.loadClass(main);
if (!mainClass.isAnnotationPresent(Plugin.class)) {
throw new PluginException("Could not find plugin annotation in " + main + " in plugin " + jarFile.getName());
}
Plugin annotation = (Plugin) mainClass.getAnnotation(Plugin.class);
LoadedPlugin registeredPlugin = getPlugin(annotation.name());
if (registeredPlugin != null) {
throw new PluginException(annotation.name() + " already has been loaded!");
}
Map<Locale, ResourceBundle> locales = getLocales(jarFile);
ZipEntry moduleEntry = jarFile.getEntry("modules.json");
if (moduleEntry != null) {
JsonElement moduleElement = parseJson(jarFile, moduleEntry);
addModules(modModulesElement, moduleElement);
}
Object instance;
try {
instance = mainClass.newInstance();
} catch (Throwable throwable) {
throw new PluginException("Could not create instance of main class in " + file.getName());
}
List<Method> loadMethods = findMethods(mainClass, LoadEvent.class);
List<Method> unloadMethods = findMethods(mainClass, UnloadEvent.class);
LoadedPlugin loadedPlugin = new LoadedPlugin(annotation.name(), annotation.version(), instance, classLoader, locales, loadMethods, unloadMethods, file);
plugins.add(loadedPlugin);
registerListener(instance, instance);
String json = The5zigMod.prettyGson.toJson(modModulesElement);
FileWriter writer = new FileWriter(The5zigMod.getModuleMaster().getFile());
writer.write(json);
writer.close();
return loadedPlugin;
}
@SuppressWarnings("EmptyForIteratorPad")
private void initInstalledApk(Context context, Apk apk, PackageInfo packageInfo, SanitizedFile apkFile)
throws IOException, CertificateEncodingException {
apk.compatible = true;
apk.versionName = packageInfo.versionName;
apk.versionCode = packageInfo.versionCode;
apk.added = this.added;
int[] minTargetMax = getMinTargetMaxSdkVersions(context, packageName);
apk.minSdkVersion = minTargetMax[0];
apk.targetSdkVersion = minTargetMax[1];
apk.maxSdkVersion = minTargetMax[2];
apk.packageName = this.packageName;
apk.requestedPermissions = packageInfo.requestedPermissions;
apk.apkName = apk.packageName + "_" + apk.versionCode + ".apk";
initInstalledObbFiles(apk);
final FeatureInfo[] features = packageInfo.reqFeatures;
if (features != null && features.length > 0) {
apk.features = new String[features.length];
for (int i = 0; i < features.length; i++) {
apk.features[i] = features[i].name;
}
}
if (!apkFile.canRead()) {
return;
}
apk.installedFile = apkFile;
JarFile apkJar = new JarFile(apkFile);
HashSet<String> abis = new HashSet<>(3);
Pattern pattern = Pattern.compile("^lib/([a-z0-9-]+)/.*");
for (Enumeration<JarEntry> jarEntries = apkJar.entries(); jarEntries.hasMoreElements(); ) {
JarEntry jarEntry = jarEntries.nextElement();
Matcher matcher = pattern.matcher(jarEntry.getName());
if (matcher.matches()) {
abis.add(matcher.group(1));
}
}
apk.nativecode = abis.toArray(new String[abis.size()]);
final JarEntry aSignedEntry = (JarEntry) apkJar.getEntry("AndroidManifest.xml");
if (aSignedEntry == null) {
apkJar.close();
throw new CertificateEncodingException("null signed entry!");
}
byte[] rawCertBytes;
// Due to a bug in android 5.0 lollipop, the inclusion of BouncyCastle causes
// breakage when verifying the signature of most .jars. For more
// details, check out https://gitlab.com/fdroid/fdroidclient/issues/111.
try {
FDroidApp.disableBouncyCastleOnLollipop();
final InputStream tmpIn = apkJar.getInputStream(aSignedEntry);
byte[] buff = new byte[2048];
//noinspection StatementWithEmptyBody
while (tmpIn.read(buff, 0, buff.length) != -1) {
/*
* NOP - apparently have to READ from the JarEntry before you can
* call getCerficates() and have it return != null. Yay Java.
*/
}
tmpIn.close();
if (aSignedEntry.getCertificates() == null
|| aSignedEntry.getCertificates().length == 0) {
apkJar.close();
throw new CertificateEncodingException("No Certificates found!");
}
final Certificate signer = aSignedEntry.getCertificates()[0];
rawCertBytes = signer.getEncoded();
} finally {
FDroidApp.enableBouncyCastleOnLollipop();
}
apkJar.close();
/*
* I don't fully understand the loop used here. I've copied it verbatim
* from getsig.java bundled with FDroidServer. I *believe* it is taking
* the raw byte encoding of the certificate & converting it to a byte
* array of the hex representation of the original certificate byte
* array. This is then MD5 sum'd. It's a really bad way to be doing this
* if I'm right... If I'm not right, I really don't know! see lines
* 67->75 in getsig.java bundled with Fdroidserver
*/
final byte[] fdroidSig = new byte[rawCertBytes.length * 2];
for (int j = 0; j < rawCertBytes.length; j++) {
byte v = rawCertBytes[j];
int d = (v >> 4) & 0xF;
fdroidSig[j * 2] = (byte) (d >= 10 ? ('a' + d - 10) : ('0' + d));
d = v & 0xF;
fdroidSig[j * 2 + 1] = (byte) (d >= 10 ? ('a' + d - 10) : ('0' + d));
}
apk.sig = Utils.hashBytes(fdroidSig, "md5");
}
public void processDownloadedFile(File downloadedFile) throws UpdateException {
InputStream indexInputStream = null;
try {
if (downloadedFile == null || !downloadedFile.exists()) {
throw new UpdateException(downloadedFile + " does not exist!");
}
// Due to a bug in Android 5.0 Lollipop, the inclusion of bouncycastle causes
// breakage when verifying the signature of the downloaded .jar. For more
// details, check out https://gitlab.com/fdroid/fdroidclient/issues/111.
FDroidApp.disableBouncyCastleOnLollipop();
JarFile jarFile = new JarFile(downloadedFile, true);
JarEntry indexEntry = (JarEntry) jarFile.getEntry(IndexUpdater.DATA_FILE_NAME);
indexInputStream = new ProgressBufferedInputStream(jarFile.getInputStream(indexEntry),
processIndexListener, (int) indexEntry.getSize());
// Process the index...
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
final SAXParser parser = factory.newSAXParser();
final XMLReader reader = parser.getXMLReader();
final RepoXMLHandler repoXMLHandler = new RepoXMLHandler(repo, createIndexReceiver());
reader.setContentHandler(repoXMLHandler);
reader.parse(new InputSource(indexInputStream));
long timestamp = repoDetailsToSave.getAsLong(RepoTable.Cols.TIMESTAMP);
if (timestamp < repo.timestamp) {
throw new UpdateException("index.jar is older that current index! "
+ timestamp + " < " + repo.timestamp);
}
signingCertFromJar = getSigningCertFromJar(indexEntry);
// JarEntry can only read certificates after the file represented by that JarEntry
// has been read completely, so verification cannot run until now...
assertSigningCertFromXmlCorrect();
commitToDb();
} catch (SAXException | ParserConfigurationException | IOException e) {
throw new UpdateException("Error parsing index", e);
} finally {
FDroidApp.enableBouncyCastleOnLollipop();
Utils.closeQuietly(indexInputStream);
if (downloadedFile != null) {
if (!downloadedFile.delete()) {
Log.w(TAG, "Couldn't delete file: " + downloadedFile.getAbsolutePath());
}
}
}
}
/**
* Adds the standard include and library subdirectories of the program to the classloader paths.
*/
/*
* private void addProgramDirectories( List< String > includeList, List< String > libList, String
* olFilepath ) { File olFile = new File( olFilepath ); if ( olFile.exists() ) { File parent =
* olFile.getParentFile(); if ( parent != null && parent.isDirectory() ) { String parentPath =
* parent.getAbsolutePath(); includeList.add( parentPath ); includeList.add( parentPath + "/include"
* ); libList.add( parentPath ); libList.add( parentPath + "/lib" ); } } }
*/
private static String parseJapManifestForMainProgram( Manifest manifest, JarFile japFile ) {
String filepath = null;
if( manifest != null ) { // See if a main program is defined through a Manifest attribute
Attributes attrs = manifest.getMainAttributes();
filepath = attrs.getValue( Constants.Manifest.MAIN_PROGRAM );
}
if( filepath == null ) { // Main program not defined, we make <japName>.ol and <japName>.olc guesses
String name = new File( japFile.getName() ).getName();
filepath = new StringBuilder()
.append( name.subSequence( 0, name.lastIndexOf( ".jap" ) ) )
.append( ".ol" )
.toString();
if( japFile.getEntry( filepath ) == null ) {
filepath = null;
filepath = filepath + 'c';
if( japFile.getEntry( filepath ) == null ) {
filepath = null;
}
}
}
if( filepath != null ) {
filepath = new StringBuilder()
.append( "jap:file:" )
.append( UriUtils.normalizeWindowsPath( japFile.getName() ) )
.append( "!/" )
.append( filepath )
.toString();
}
return filepath;
}
/**
* Internal helper to initialize everything for this file
*
* @param packageName
*/
private void init(String packageName) {
if (url != null) { // null in case of resources not found.
String fileName = url.getFile();
if (url.getProtocol().equals("jar")) {
int pathDelim = fileName.indexOf("!");
if (WebappHelper.getContextRoot().startsWith("/")) {
// First lookup in cache
size = cachedJarResourceSize.get(fileName);
lastModified = cachedJarResourceLastModified.get(fileName);
if (size == null || lastModified == null) {
// Not found in cache, read from jar and add to cache
// Unix style: path should look like //my/absolute/path
String jarPath = "/" + fileName.substring(5, pathDelim);
// Rel path must not start with "!/", remove it
String relPath = fileName.substring(pathDelim + 2);
try {
// Get last modified and file size form jar entry
File jarFile = new File(jarPath);
JarFile jar = new JarFile(jarFile);
ZipEntry entry = jar.getEntry(relPath);
if (entry == null) {
log.warn("jar resource at location '" + location + "' and package " + packageName + " was not found, could not resolve entry relPath::"
+ relPath, null);
} else {
size = new Long(entry.getSize());
// Last modified of jar - getTime on jar entry is not stable
lastModified = Long.valueOf(jarFile.lastModified());
// Add to cache - no need to synchronize, just overwrite
cachedJarResourceSize.put(fileName, size);
cachedJarResourceLastModified.put(fileName, lastModified);
}
} catch (IOException e) {
log.warn("jar resource at location '" + location + "' and package " + packageName + " was not found!", e);
}
}
} else {
// For windows ignore the jar size and last modified, it
// works also without those parameters. Windows should not
// be used in production
this.lastModified = WebappHelper.getTimeOfServerStartup();
}
} else {
// Get last modified and file size
File f = new File(fileName);
long lm = f.lastModified();
this.lastModified = (lm != 0 ? lm : WebappHelper.getTimeOfServerStartup());
if (f.exists()) {
size = new Long(f.length());
}
}
if (log.isDebugEnabled()) {
log.debug("resource found at URL::" + this.url + " for package::" + packageName + " and location::" + location + ", filesize::" + size
+ " lastModified::" + lastModified, null);
}
} else {
// resource was not found
log.warn("resource at location '" + location + "' and package " + packageName + " was not found!", null);
}
}
/** Build the {@link JarScriptArchive}. */
public JarScriptArchive build() throws IOException {
ScriptModuleSpec buildModuleSpec = moduleSpec;
String moduleSpecEntry = null;
if (buildModuleSpec == null){
String buildSpecFileName = specFileName != null ? specFileName : DEFAULT_MODULE_SPEC_FILE_NAME;
// attempt to find a module spec in the jar file
JarFile jarFile = new JarFile(jarPath.toFile());
try {
ZipEntry zipEntry = jarFile.getEntry(buildSpecFileName);
if (zipEntry != null) {
moduleSpecEntry = buildSpecFileName;
InputStream inputStream = jarFile.getInputStream(zipEntry);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
IOUtils.copy(inputStream, outputStream);
byte[] bytes = outputStream.toByteArray();
if (bytes != null && bytes.length > 0) {
String json = new String(bytes, Charsets.UTF_8);
ScriptModuleSpecSerializer buildSpecSerializer = specSerializer != null ? specSerializer :
DEFAULT_SPEC_SERIALIZER;
buildModuleSpec = buildSpecSerializer.deserialize(json);
}
}
} finally {
IOUtils.closeQuietly(jarFile);
}
// create a default module spec
if (buildModuleSpec == null) {
String jarFileName = this.jarPath.getFileName().toString();
if (jarFileName.endsWith(JAR_FILE_SUFFIX)) {
jarFileName = jarFileName.substring(0, jarFileName.lastIndexOf(JAR_FILE_SUFFIX));
}
ModuleId moduleId = ModuleId.fromString(jarFileName);
buildModuleSpec = new ScriptModuleSpec.Builder(moduleId).build();
}
}
long buildCreateTime = createTime;
if (buildCreateTime <= 0) {
buildCreateTime = Files.getLastModifiedTime(jarPath).toMillis();
}
return new JarScriptArchive(buildModuleSpec, jarPath, moduleSpecEntry, buildCreateTime);
}