/**
* OpenAtlasForAndroid Project
* The MIT License (MIT) Copyright (OpenAtlasForAndroid) 2015 Bunny Blue,achellies
* <p>
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software
* without restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
* <p>
* The above copyright notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
* <p>
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* @author BunnyBlue
**/
package com.openatlas.framework;
import com.openatlas.bundleInfo.BundleInfoList;
import com.openatlas.framework.bundlestorage.Archive;
import com.openatlas.framework.bundlestorage.BundleArchiveRevision.DexLoadException;
import com.openatlas.hack.OpenAtlasHacks;
import com.openatlas.log.Logger;
import com.openatlas.log.LoggerFactory;
import org.osgi.framework.BundleException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.jar.Attributes;
/***
* bundle class loader ,load class from bundle
**/
public final class BundleClassLoader extends ClassLoader {
private static final List<URL> EMPTY_LIST;
static final HashSet<String> FRAMEWORK_PACKAGES;
static final Logger log;
final Archive archive;
BundleImpl bundle;
List<BundleClassLoader> dependencyClsLoaders;
/***
* remove next version
*********/
@SuppressWarnings("unused")
@Deprecated
private static final class BundleURLHandler extends URLStreamHandler {
private final InputStream inputStream;
private BundleURLHandler(final InputStream inputStream) {
this.inputStream = new InputStream() {
@Override
public int read() throws IOException {
return inputStream.read();
}
@Override
public int read(byte[] buffer) throws IOException {
return inputStream.read(buffer);
}
};
}
@Override
protected URLConnection openConnection(URL url) throws IOException {
return new URLConnection(url) {
@Override
public void connect() throws IOException {
}
@Override
public InputStream getInputStream() throws IOException {
return inputStream;
}
};
}
@Override
protected int hashCode(URL url) {
return this.inputStream.hashCode();
}
}
static {
log = LoggerFactory.getInstance("BundleClassLoader");
FRAMEWORK_PACKAGES = new HashSet<String>();
FRAMEWORK_PACKAGES.add(OpenAtlasInternalConstant.OPENATLAS_FRAMEWORK_PACKAGE);
FRAMEWORK_PACKAGES.add("org.osgi.framework");
FRAMEWORK_PACKAGES.add("org.osgi.service.packageadmin");
FRAMEWORK_PACKAGES.add("org.osgi.service.startlevel");
EMPTY_LIST = new ArrayList<URL>();
}
BundleClassLoader(BundleImpl bundleImpl) throws BundleException {
super(Object.class.getClassLoader());
// this.exports = new String[0];
// this.imports = new String[0];
// this.requires = new String[0];
// this.activatorClassName = null;
// this.activator = null;
this.bundle = bundleImpl;
this.archive = bundleImpl.archive;
if (this.archive == null) {
throw new BundleException("Not Component valid bundle: " + bundleImpl.location);
}
}
public BundleImpl getBundle() {
return this.bundle;
}
@Deprecated
private void checkExecutionEnviroment(String[] requireEnv, String[] execEnv)
throws BundleException {
if (requireEnv.length != 0) {
Set hashSet = new HashSet(Arrays.asList(execEnv));
int i = 0;
while (i < requireEnv.length) {
if (!hashSet.contains(requireEnv[i])) {
i++;
} else {
return;
}
}
throw new BundleException("Platform does not provide EEs " + Arrays.asList(requireEnv));
}
}
boolean resolveBundle(boolean resolve, HashSet<BundleClassLoader> hashSet) throws BundleException {
if (Framework.DEBUG_CLASSLOADING && log.isInfoEnabled()) {
log.info("BundleClassLoader: Resolving " + this.bundle + (resolve ? " (critical)" : " (not critical)"));
}
List<String> pkgs=BundleInfoList.getInstance().
getDependencyForBundle(bundle.getLocation());
dependencyClsLoaders=new ArrayList<BundleClassLoader>(pkgs.size());
for (int i=0;i<pkgs.size();i++){
dependencyClsLoaders.add((BundleClassLoader) OpenAtlas.getInstance().getBundleClassLoader(pkgs.get(i)));
}
// HashSet hashSetExports=null;
// if (this.exports.length > 0) {
// hashSetExports = new HashSet(this.exports.length);
// for (String parsePackageString : this.exports) {
// hashSetExports.add(Package.parsePackageString(parsePackageString)[0]);
// }
//
// }
// if (this.imports.length > 0) {
// if (this.importDelegations == null) {
// this.importDelegations = new HashMap(this.imports.length);
// }
// for (int i = 0; i < this.imports.length; i++) {
// String obj = Package.parsePackageString(this.imports[i])[0];
// if (!FRAMEWORK_PACKAGES.contains(obj)
// && this.importDelegations.get(obj) == null
// && (hashSetExports == null || !hashSetExports.contains(obj))) {
// BundleClassLoader bundleClassLoader = Framework.getImport(
// this.bundle, this.imports[i], resolve, hashSet);
// if (bundleClassLoader != null) {
// if (bundleClassLoader != this) {
// this.importDelegations.put(obj, bundleClassLoader);
// }
// } else if (resolve) {
// throw new BundleException("Unsatisfied import "
// + this.imports[i] + " for bundle "
// + this.bundle.toString(),
// new ClassNotFoundException(
// "Unsatisfied import "
// + this.imports[i]));
// } else {
// if (this.exports.length > 0) {
// Framework.export(this, this.exports, false);
// }
// if (!Framework.DEBUG_CLASSLOADING
// || !log.isInfoEnabled()) {
// return false;
// }
// log.info("BundleClassLoader: Missing import "
// + this.imports[i]
// + ". Resolving attempt terminated unsuccessfully.");
// return false;
// }
// }
// }
// }
// if (this.exports.length > 0) {
// if (this.importDelegations == null) {
// this.importDelegations = new HashMap(this.imports.length);
// }
// for (int i = 0; i < this.exports.length; i++) {
// BundleClassLoader bundleClassLoader = Framework.getImport(
// this.bundle,
// Package.parsePackageString(this.exports[i])[0], false,
// null);
// if (!(bundleClassLoader == null || bundleClassLoader == this)) {
// this.importDelegations.put(
// Package.parsePackageString(this.exports[i])[0],
// bundleClassLoader);
// }
// }
// }
// if (this.exports.length > 0) {
// Framework.export(this, this.exports, true);
// }
return true;
}
void cleanup(boolean staleExportedPackage) {
ArrayList arrayList = new ArrayList();
if (this.bundle != null) {
// if (staleExportedPackage) {
// this.bundle.staleExportedPackages = (Package[]) arrayList
// .toArray(new Package[arrayList.size()]);
// } else {
// this.bundle.staleExportedPackages = null;
// }
}
// if (this.importDelegations != null) {
// String[] delegations = this.importDelegations.keySet()
// .toArray(new String[this.importDelegations.size()]);
// for (String mImportDelegation : delegations) {
// Package exportPackage = Framework.exportedPackages
// .get(new Package(mImportDelegation, null, false));
// if (!(exportPackage == null || exportPackage.importingBundles == null)) {
// exportPackage.importingBundles.remove(this.bundle);
// if (exportPackage.importingBundles.isEmpty()) {
// exportPackage.importingBundles = null;
// if (exportPackage.removalPending) {
// Framework.exportedPackages.remove(exportPackage);
// }
// }
// }
// }
// }
// this.importDelegations = null;
// this.activator = null;
if (staleExportedPackage) {
if (arrayList.size() == 0) {
this.bundle = null;
}
}
}
@Override
protected Class<?> findClass(String clazz) throws ClassNotFoundException {
if (FRAMEWORK_PACKAGES.contains(packageOf(clazz))) {
return Framework.systemClassLoader.loadClass(clazz);
}
Class<?> findOwnClass = findOwnClass(clazz);
if (findOwnClass != null) {
return findOwnClass;
}
for (int i=0;i<dependencyClsLoaders.size();i++) {
BundleClassLoader dependencyLoader = dependencyClsLoaders.get(i);
if (dependencyLoader != null) {
findOwnClass = findDelegatedClass(dependencyLoader, clazz);
if (findOwnClass != null) {
return findOwnClass;
}
}
}
try {
findOwnClass = Framework.systemClassLoader.loadClass(clazz);
if (findOwnClass != null) {
return findOwnClass;
}
} catch (Exception e) {
}
throw new ClassNotFoundException("Can't find class " + clazz
+ " in BundleClassLoader: " + this.bundle.getLocation());
}
private Class<?> findOwnClass(String clazz) {
try {
return this.archive.findClass(clazz, this);
} catch (Exception e) {
if (!(e instanceof DexLoadException)) {
return null;
}
throw ((DexLoadException) e);
}
}
private static Class<?> findDelegatedClass(
BundleClassLoader bundleClassLoader, String clazz) {
Class<?> findLoadedClass;
synchronized (bundleClassLoader) {
findLoadedClass = bundleClassLoader.findLoadedClass(clazz);
if (findLoadedClass == null) {
findLoadedClass = bundleClassLoader.findOwnClass(clazz);
}
}
return findLoadedClass;
}
@Override
protected URL findResource(String name) {
String stripTrailing = stripTrailing(name);
List findOwnResources = findOwnResources(stripTrailing, false);
if (findOwnResources.size() > 0) {
return (URL) findOwnResources.get(0);
}
return null;
// List findImportedResources = findImportedResources(stripTrailing, false);
// return findImportedResources.size() > 0 ? (URL) findImportedResources
// .get(0) : null;
}
@Override
protected Enumeration<URL> findResources(String name) {
String stripTrailing = stripTrailing(name);
Collection findOwnResources = findOwnResources(stripTrailing, true);
// findOwnResources.addAll(findImportedResources(stripTrailing, true));
return Collections.enumeration(findOwnResources);
}
private List<URL> findOwnResources(String name, boolean z) {
try {
return this.archive.getResources(name);
} catch (IOException e) {
e.printStackTrace();
return EMPTY_LIST;
}
}
@Override
protected String findLibrary(String nickname) {
String mapLibraryName = System.mapLibraryName(nickname);
File findLibrary = this.archive.findLibrary(mapLibraryName);
if (findLibrary != null) {
return findLibrary.getAbsolutePath();
}
try {
return (String) OpenAtlasHacks.ClassLoader_findLibrary.invoke(
Framework.systemClassLoader, nickname);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@Override
public String toString() {
return "BundleClassLoader[Bundle" + this.bundle + "]";
}
private static String[] readProperty(Attributes attributes, String name)
throws BundleException {
String value = attributes.getValue(name);
if (value == null || !value.equals("")) {
return splitString(value);
}
return new String[0];
}
private static String[] splitString(String string) {
int i = 0;
if (string == null) {
return new String[0];
}
StringTokenizer stringTokenizer = new StringTokenizer(string, ",");
if (stringTokenizer.countTokens() == 0) {
return new String[]{string};
}
String[] strArr = new String[stringTokenizer.countTokens()];
while (i < strArr.length) {
strArr[i] = stringTokenizer.nextToken().trim();
i++;
}
return strArr;
}
private static String stripTrailing(String name) {
return (name.startsWith("/") || name.startsWith("\\")) ? name.substring(1)
: name;
}
private static String packageOf(String name) {
int lastIndexOf = name.lastIndexOf(46);
return lastIndexOf > -1 ? name.substring(0, lastIndexOf) : "";
}
}