blob: 68dba2c51486fe74092b313476f2478568bc6b17 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006 Cognos Incorporated, IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
*******************************************************************************/
package org.eclipse.osgi.framework.internal.protocol;
import java.lang.reflect.Method;
import java.util.*;
import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.osgi.framework.BundleContext;
import org.osgi.service.packageadmin.PackageAdmin;
import org.osgi.util.tracker.ServiceTracker;
/*
* An abstract class for handler factory impls (Stream and Content) that can
* handle environments running multiple osgi frameworks with the same VM.
*/
public abstract class MultiplexingFactory {
protected static final String PACKAGEADMINCLASS = "org.osgi.service.packageadmin.PackageAdmin"; //$NON-NLS-1$
protected BundleContext context;
protected FrameworkAdaptor adaptor;
private List factories; // list of multiplexed factories
private ServiceTracker packageAdminTracker;
// used to get access to the protected SecurityManager#getClassContext method
private static class InternalSecurityManager extends SecurityManager {
public Class[] getClassContext() {
return super.getClassContext();
}
}
private static InternalSecurityManager internalSecurityManager = new InternalSecurityManager();
MultiplexingFactory(BundleContext context, FrameworkAdaptor adaptor) {
this.context = context;
this.adaptor = adaptor;
packageAdminTracker = new ServiceTracker(context, PACKAGEADMINCLASS, null);
packageAdminTracker.open();
}
abstract public void setParentFactory(Object parentFactory);
abstract public Object getParentFactory();
public synchronized boolean isMultiplexing() {
return factories != null;
}
public synchronized void register(Object factory) {
if (factories == null)
factories = new LinkedList();
// set parent for each factory so they can do proper delegation
try {
Class clazz = factory.getClass();
Method setParentFactory = clazz.getMethod("setParentFactory", new Class[] {Object.class}); //$NON-NLS-1$
setParentFactory.invoke(factory, new Object[] {getParentFactory()});
} catch (Exception e) {
adaptor.getFrameworkLog().log(new FrameworkLogEntry(MultiplexingFactory.class.getName(), FrameworkLogEntry.ERROR, 0, "register", FrameworkLogEntry.ERROR, e, null)); //$NON-NLS-1$
throw new RuntimeException(e.getMessage());
}
factories.add(factory);
}
public synchronized void unregister(Object factory) {
factories.remove(factory);
if (factories.isEmpty())
factories = null;
// close the service tracker
try {
// this is brittle; if class does not directly extend MultplexingFactory then this method will not exist, but we do not want a public method here
Method closeTracker = factory.getClass().getSuperclass().getDeclaredMethod("closePackageAdminTracker", null); //$NON-NLS-1$
closeTracker.setAccessible(true); // its a private method
closeTracker.invoke(factory, null);
} catch (Exception e) {
adaptor.getFrameworkLog().log(new FrameworkLogEntry(MultiplexingFactory.class.getName(), FrameworkLogEntry.ERROR, 0, "unregister", FrameworkLogEntry.ERROR, e, null)); //$NON-NLS-1$
throw new RuntimeException(e.getMessage());
}
}
public synchronized Object designateSuccessor() {
Object parentFactory = getParentFactory();
if (factories == null || factories.isEmpty())
return parentFactory;
Object successor = factories.remove(0);
try {
Class clazz = successor.getClass();
Method register = clazz.getMethod("register", new Class[] {Object.class}); //$NON-NLS-1$
for (Iterator it = factories.iterator(); it.hasNext();) {
register.invoke(successor, new Object[] {it.next()});
}
} catch (Exception e) {
adaptor.getFrameworkLog().log(new FrameworkLogEntry(MultiplexingFactory.class.getName(), FrameworkLogEntry.ERROR, 0, "designateSuccessor", FrameworkLogEntry.ERROR, e, null)); //$NON-NLS-1$
throw new RuntimeException(e.getMessage());
}
factories = null;
closePackageAdminTracker(); // close tracker
return successor;
}
private void closePackageAdminTracker() {
packageAdminTracker.close();
}
public synchronized Object findAuthorizedFactory(List ignoredClasses) {
Class[] classStack = internalSecurityManager.getClassContext();
for (int i = 0; i < classStack.length; i++) {
Class clazz = classStack[i];
if (clazz == InternalSecurityManager.class || clazz == MultiplexingFactory.class || ignoredClasses.contains(clazz))
continue;
if (hasAuthority(clazz))
return this;
if (factories == null)
continue;
for (Iterator it = factories.iterator(); it.hasNext();) {
Object factory = it.next();
try {
Method hasAuthorityMethod = factory.getClass().getMethod("hasAuthority", new Class[] {Class.class}); //$NON-NLS-1$
if (((Boolean) hasAuthorityMethod.invoke(factory, new Object[] {clazz})).booleanValue()) {
return factory;
}
} catch (Exception e) {
adaptor.getFrameworkLog().log(new FrameworkLogEntry(MultiplexingFactory.class.getName(), FrameworkLogEntry.ERROR, 0, "findAuthorizedURLStreamHandler-loop", FrameworkLogEntry.ERROR, e, null)); //$NON-NLS-1$
throw new RuntimeException(e.getMessage());
}
}
}
return null;
}
public boolean hasAuthority(Class clazz) {
PackageAdmin packageAdminService = (PackageAdmin) packageAdminTracker.getService();
if (packageAdminService != null) {
return packageAdminService.getBundle(clazz) != null;
}
return false;
}
}