/*******************************************************************************
* Copyright (c) 2013 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
* and Eclipse Distribution License v1.0 which accompany this distribution.
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Jan S. Rellermeyer, IBM Research - initial API and implementation
*******************************************************************************/
package org.eclipse.concierge;
import java.io.File;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Permission;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.concierge.BundleImpl.Revision;
import org.eclipse.concierge.Concierge.BundleContextImpl;
import org.eclipse.concierge.Concierge.ServiceListenerEntry;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.FrameworkListener;
import org.osgi.framework.ServicePermission;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.wiring.BundleRevision;
import org.osgi.framework.wiring.BundleRevisions;
import org.osgi.framework.wiring.BundleWiring;
public abstract class AbstractBundle implements Bundle, BundleRevisions {
protected static final short AUTOSTART_STOPPED = 0;
protected static final short AUTOSTART_STARTED_WITH_DECLARED = 1;
protected static final short AUTOSTART_STARTED_WITH_EAGER = 2;
/**
* the bundle id.
*/
protected long bundleId;
protected ArrayList<BundleRevision> revisions = new ArrayList<BundleRevision>();
protected Revision currentRevision;
/**
* the bundle location.
*/
protected String location;
/**
* the bundle state.
*/
protected int state;
/**
* time when bundle was last modified (milliseconds since Jan. 1. 1970)
*/
protected long lastModified;
/**
* List of services registered by this bundle. Is initialized in a lazy way.
*/
protected List<ServiceReference<?>> registeredServices;
/**
* the storage location.
*/
protected String storageLocation;
/**
* the current start level.
*/
protected int startlevel;
/**
* is bundle marked to be started persistently.
*/
protected short autostart = AUTOSTART_STOPPED;
/**
* the bundle context.
*/
protected BundleContextImpl context;
/**
* the protection domain of this bundle.
*/
protected ProtectionDomain domain;
/**
* List of framework listeners registered by this bundle. Is initialized in
* a lazy way.
*/
protected List<FrameworkListener> registeredFrameworkListeners;
/**
* List of service listeners registered by this bundle. Is initialized in a
* lazy way.
*/
protected List<ServiceListenerEntry> registeredServiceListeners;
/**
* get the state of the bundle.
*
* @return the state.
* @see org.osgi.framework.Bundle#getState()
* @category Bundle
*/
public final int getState() {
return state;
}
/**
* @see org.osgi.framework.Bundle#getBundleId()
* @category Bundle
*/
public final long getBundleId() {
return bundleId;
}
/**
* get the bundle location.
*
* @return the bundle location.
* @see org.osgi.framework.Bundle#getLocation()
* @category Bundle
*/
public final String getLocation() {
if (isSecurityEnabled()) {
// TODO: check AdminPermission(this,METADATA)
}
return location;
}
/**
* get the registered services of the bundle.
*
* @return the service reference array.
* @see org.osgi.framework.Bundle#getRegisteredServices()
* @category Bundle
*/
public final ServiceReference<?>[] getRegisteredServices() {
if (state == UNINSTALLED) {
throw new IllegalStateException("Bundle " + toString()
+ "has been uninstalled.");
}
if (registeredServices == null) {
return null;
}
/*
* FIXME: not the same page anymore --> core specifications page=91: If
* the Java runtime supports permissions, a ServiceReference object to a
* service is included in the returned list only if the caller has the
* ServicePermission to get the service using at least one of the names
* classes the service was registered under.
*/
if (isSecurityEnabled()) {
return checkPermissions(registeredServices
.toArray(new ServiceReferenceImpl[registeredServices.size()]));
} else {
return registeredServices
.toArray(new ServiceReference[registeredServices.size()]);
}
}
/**
* check if the bundle has a certain permission.
*
* @param permission
* the permission object
* @return true if the bundle has the permission.
* @see org.osgi.framework.Bundle#hasPermission(java.lang.Object)
* @category Bundle
*/
public final boolean hasPermission(final Object permission) {
checkBundleNotUninstalled();
if (isSecurityEnabled()) {
return permission instanceof Permission ? domain.getPermissions()
.implies((Permission) permission) : false;
} else {
return true;
}
}
/**
*
* @see org.osgi.framework.Bundle#getLastModified()
* @category Bundle
*/
public final long getLastModified() {
return lastModified;
}
/**
* get bundle context
*
* @return the bundle context if it exists, null otherwise
* @see org.osgi.framework.Bundle#getBundleContext()
* @category Bundle
*/
public final BundleContext getBundleContext() {
// check permissions
if (isSecurityEnabled()) {
// TODO: check AdminPermission(this,CONTEXT)
}
if (state == STARTING || state == ACTIVE || state == STOPPING) {
return context;
}
return null;
}
@SuppressWarnings("unchecked")
public <A> A adapt(final Class<A> type) {
// BundleRevisions
// BundleStartLevel
if (type.isInstance(this)) {
return (A) this;
}
// AccessControlContext
// TODO: implement
// BundleContext
if (type == BundleContext.class) {
return (A) context;
}
// BundleRevision
if (type == BundleRevision.class) {
return (A) currentRevision;
}
// BundleWiring
if (type == BundleWiring.class) {
return currentRevision != null ? (A) currentRevision.getWiring()
: null;
}
return null;
}
/**
* @see java.lang.Comparable#compareTo(java.lang.Object)
* @category Bundle
*/
public final int compareTo(final Bundle o) {
return (int) (o.getBundleId() - bundleId);
}
// BundleRevisions
/**
* @see org.osgi.framework.wiring.BundleRevisions#getRevisions()
* @category BundleRevisions
*/
public final List<BundleRevision> getRevisions() {
return Collections.unmodifiableList(revisions);
}
// BundleReference
/**
* @see org.osgi.framework.BundleReference#getBundle()
* @category BundleReference
*/
public final Bundle getBundle() {
return this;
}
/**
* @see org.osgi.framework.Bundle#getDataFile(java.lang.String)
* @category Bundle
*/
public final File getDataFile(final String filename) {
// according to OSGi R5 spec 10.1.6.16: return null if fragment
if (context != null) {
return context.getDataFile(filename);
} else {
return null;
}
}
protected abstract boolean isSecurityEnabled();
protected final void updateLastModified() {
final long newMod = System.currentTimeMillis();
// ensure strict monotonicity on system with a slow clock
lastModified = newMod > lastModified ? newMod : ++lastModified;
}
/**
* remove all ServiceReferences for which the requesting bundle does not
* have appropriate permissions
*
* @param refs
* the references.
* @return the permitted references.
*/
protected static final ServiceReference<?>[] checkPermissions(
final ServiceReferenceImpl<?>[] refs) {
final List<ServiceReferenceImpl<?>[]> results = new ArrayList<ServiceReferenceImpl<?>[]>(
refs.length);
final AccessControlContext controller = AccessController.getContext();
for (int i = 0; i < refs.length; i++) {
final String[] interfaces = (String[]) refs[i].properties
.get(Constants.OBJECTCLASS);
for (int j = 0; j < interfaces.length; j++) {
try {
controller.checkPermission(new ServicePermission(
interfaces[j], ServicePermission.GET));
results.add(refs);
break;
} catch (final SecurityException se) {
// does not have the permission, try with the next interface
}
}
}
return results.toArray(new ServiceReference[results.size()]);
}
protected final void checkBundleNotUninstalled()
throws IllegalArgumentException {
if (state == Bundle.UNINSTALLED) {
throw new IllegalArgumentException("Bundle " + toString()
+ " has been uninstalled");
}
}
}