package org.eclipse.osgi.internal.framework;
import java.io.IOException;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import org.eclipse.osgi.framework.eventmgr.ListenerQueue;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.eclipse.osgi.framework.util.SecureAction;
import org.eclipse.osgi.internal.framework.legacy.PackageAdminImpl;
import org.eclipse.osgi.internal.framework.legacy.StartLevelImpl;
import org.eclipse.osgi.internal.hookregistry.ClassLoaderHook;
import org.eclipse.osgi.internal.hookregistry.HookRegistry;
import org.eclipse.osgi.internal.location.EquinoxLocations;
import org.eclipse.osgi.internal.log.EquinoxLogServices;
import org.eclipse.osgi.internal.messages.Msg;
import org.eclipse.osgi.internal.serviceregistry.ServiceRegistry;
import org.eclipse.osgi.signedcontent.SignedContentFactory;
import org.eclipse.osgi.storage.Storage;
import org.eclipse.osgi.util.ManifestElement;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.AdminPermission;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
import org.osgi.service.packageadmin.PackageAdmin;
import org.osgi.service.startlevel.StartLevel;
import org.osgi.util.tracker.ServiceTracker;
@SuppressWarnings("deprecation")
public class EquinoxContainer implements ThreadFactory, Runnable {
public static final String NAME = "org.eclipse.osgi";
static final SecureAction secureAction = AccessController.doPrivileged(SecureAction.createSecureAction());
private final EquinoxConfiguration equinoxConfig;
private final EquinoxLogServices logServices;
private final Storage storage;
private final PackageAdmin packageAdmin;
private final StartLevel startLevel;
private final Set<String> bootDelegation;
private final String[] bootDelegationStems;
private final boolean bootDelegateAll;
private final boolean isProcessClassRecursionSupportedByAll;
private final EquinoxEventPublisher eventPublisher;
private final Object monitor = new Object();
private final ClassLoader bootLoader;
private ServiceRegistry serviceRegistry;
private ContextFinder contextFinder;
private ServiceTracker<SignedContentFactory, SignedContentFactory> signedContentFactory;
private ScheduledExecutorService executor;
private StorageSaver storageSaver;
public EquinoxContainer(Map<String, ?> configuration) {
ClassLoader platformClassLoader = null;
try {
Method getPlatformClassLoader = ClassLoader.class.getMethod("getPlatformClassLoader");
platformClassLoader = (ClassLoader) getPlatformClassLoader.invoke(null);
} catch (Throwable t) {
platformClassLoader = new ClassLoader(Object.class.getClassLoader()) {
};
}
this.bootLoader = platformClassLoader;
this.equinoxConfig = new EquinoxConfiguration(configuration, new HookRegistry(this));
this.logServices = new EquinoxLogServices(this.equinoxConfig);
this.equinoxConfig.logMessages(this.logServices);
this.equinoxConfig.getHookRegistry().initialize();
try {
this.storage = Storage.createStorage(this);
} catch (IOException | BundleException e) {
throw new RuntimeException("Error initializing storage.", e);
}
this.packageAdmin = new PackageAdminImpl(storage.getModuleContainer());
this.startLevel = new StartLevelImpl(storage.getModuleContainer());
this.eventPublisher = new EquinoxEventPublisher(this);
String bootDelegationProp = equinoxConfig.getConfiguration(Constants.FRAMEWORK_BOOTDELEGATION);
String[] bootPackages = ManifestElement.getArrayFromList(bootDelegationProp, ",");
HashSet<String> exactMatch = new HashSet<>(bootPackages.length);
List<String> stemMatch = new ArrayList<>(bootPackages.length);
boolean delegateAllValue = false;
for (String bootPackage : bootPackages) {
if (bootPackage.equals("*")) {
delegateAllValue = true;
exactMatch.clear();
stemMatch.clear();
break;
} else if (bootPackage.endsWith("*")) {
if (bootPackage.length() > 2 && bootPackage.endsWith(".*")) {
stemMatch.add(bootPackage.substring(0, bootPackage.length() - 1));
}
} else {
exactMatch.add(bootPackage);
}
}
bootDelegateAll = delegateAllValue;
bootDelegation = exactMatch;
bootDelegationStems = stemMatch.isEmpty() ? null : stemMatch.toArray(new String[stemMatch.size()]);
boolean supportRecursion = true;
for (ClassLoaderHook hook : equinoxConfig.getHookRegistry().getClassLoaderHooks()) {
supportRecursion &= hook.isProcessClassRecursionSupported();
}
isProcessClassRecursionSupportedByAll = supportRecursion;
}
public Storage getStorage() {
return storage;
}
public EquinoxConfiguration getConfiguration() {
return equinoxConfig;
}
public EquinoxLocations getLocations() {
return equinoxConfig.getEquinoxLocations();
}
public EquinoxLogServices getLogServices() {
return logServices;
}
public PackageAdmin getPackageAdmin() {
return packageAdmin;
}
public StartLevel getStartLevel() {
return startLevel;
}
public SignedContentFactory getSignedContentFactory() {
ServiceTracker<SignedContentFactory, SignedContentFactory> current;
synchronized (this.monitor) {
current = signedContentFactory;
}
return current == null ? null : current.getService();
}
public boolean isBootDelegationPackage(String name) {
if (bootDelegateAll)
return true;
if (bootDelegation.contains(name))
return true;
if (bootDelegationStems != null)
for (String bootDelegationStem : bootDelegationStems) {
if (name.startsWith(bootDelegationStem)) {
return true;
}
}
return false;
}
public boolean isProcessClassRecursionSupportedByAll() {
return isProcessClassRecursionSupportedByAll;
}
void init() {
eventPublisher.init();
synchronized (this.monitor) {
serviceRegistry = new ServiceRegistry(this);
initializeContextFinder();
executor = Executors.newScheduledThreadPool(1, this);
executor.execute(this);
storageSaver = new StorageSaver(this);
}
}
void close() {
StorageSaver currentSaver;
Storage currentStorage;
ScheduledExecutorService currentExecutor;
synchronized (this.monitor) {
serviceRegistry = null;
currentSaver = storageSaver;
currentStorage = storage;
currentExecutor = executor;
}
currentSaver.close();
currentStorage.close();
currentExecutor.shutdown();
}
private void initializeContextFinder() {
Thread current = Thread.currentThread();
try {
ClassLoader parent = null;
String type = equinoxConfig.getConfiguration(EquinoxConfiguration.PROP_CONTEXTCLASSLOADER_PARENT);
if (EquinoxConfiguration.CONTEXTCLASSLOADER_PARENT_APP.equals(type))
parent = ClassLoader.getSystemClassLoader();
else if (EquinoxConfiguration.CONTEXTCLASSLOADER_PARENT_BOOT.equals(type))
parent = bootLoader;
else if (EquinoxConfiguration.CONTEXTCLASSLOADER_PARENT_FWK.equals(type))
parent = EquinoxContainer.class.getClassLoader();
else if (EquinoxConfiguration.CONTEXTCLASSLOADER_PARENT_EXT.equals(type)) {
ClassLoader appCL = ClassLoader.getSystemClassLoader();
if (appCL != null)
parent = appCL.getParent();
} else {
parent = current.getContextClassLoader();
}
contextFinder = new ContextFinder(parent, bootLoader);
current.setContextClassLoader(contextFinder);
return;
} catch (Exception e) {
logServices.log(NAME, FrameworkLogEntry.INFO, NLS.bind(Msg.CANNOT_SET_CONTEXTFINDER, null), e);
}
}
public EquinoxEventPublisher getEventPublisher() {
synchronized (this.monitor) {
return eventPublisher;
}
}
ScheduledExecutorService getScheduledExecutor() {
synchronized (this.monitor) {
return executor;
}
}
public ServiceRegistry getServiceRegistry() {
synchronized (this.monitor) {
return serviceRegistry;
}
}
public ContextFinder getContextFinder() {
synchronized (this.monitor) {
return contextFinder;
}
}
public <K, V, E> ListenerQueue<K, V, E> newListenerQueue() {
return eventPublisher.newListenerQueue();
}
void checkAdminPermission(Bundle bundle, String action) {
if (bundle == null)
return;
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkPermission(new AdminPermission(bundle, action));
}
public void handleRuntimeError(Throwable t) {
}
void systemStart(BundleContext bc) {
synchronized (this.monitor) {
signedContentFactory = new ServiceTracker<>(bc, SignedContentFactory.class, null);
}
signedContentFactory.open();
}
void systemStop(BundleContext bc) {
ServiceTracker<SignedContentFactory, SignedContentFactory> current;
synchronized (this.monitor) {
current = signedContentFactory;
}
if (current != null) {
current.close();
}
}
@Override
public String toString() {
String UUID = equinoxConfig == null ? null : equinoxConfig.getConfiguration(Constants.FRAMEWORK_UUID);
return "Equinox Container: " + UUID;
}
StorageSaver getStorageSaver() {
synchronized (this.monitor) {
return storageSaver;
}
}
@Override
public Thread newThread(Runnable r) {
String type = equinoxConfig.getConfiguration(EquinoxConfiguration.PROP_ACTIVE_THREAD_TYPE, EquinoxConfiguration.ACTIVE_THREAD_TYPE_NORMAL);
Thread t = new Thread(r, "Active Thread: " + toString());
if (EquinoxConfiguration.ACTIVE_THREAD_TYPE_NORMAL.equals(type)) {
t.setDaemon(false);
} else {
t.setDaemon(true);
}
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
@Override
public void run() {
}
public ClassLoader getBootLoader() {
return bootLoader;
}
}