blob: c74cfda2949ed8d9c1e28d8144f47e26c6706d3a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.clerezza.permissiondescriptions;
import java.net.URL;
import java.security.Permission;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.apache.clerezza.utils.IteratorMerger;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This binds all implementations of
* <code>PermissionDescriptionsProvider</code>, and gathers their
* <code>PermissionDescription</code>s. Furthermore the gatherer scans all
* activaded bundles for
* <code>Permission</code>s which are annonated with the
* <code>PermissionInfo</code> annotation and generates
* <code>PermissionDescription</code>s for them. This service provides methods
* to retrieve the gathered
* <code>PermissionDescription</code>s and also methods to retrieve all
* unannotated
* <code>Permission</code> found in the activated bundles. If new bundles are
* started then they are also scanned.
*
* @author mir
*/
@Component(immediate = true)
@Service(PermissionGatherer.class)
@Reference(name = "permissionProvider", policy = ReferencePolicy.DYNAMIC,
referenceInterface = PermissionDescriptionsProvider.class, cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE)
public class PermissionGatherer implements BundleListener {
private final Logger logger = LoggerFactory.getLogger(getClass());
private Map<Bundle, Collection<Class<? extends Permission>>> bundle2PermissionClassesMap =
Collections.synchronizedMap(new HashMap<Bundle, Collection<Class<? extends Permission>>>());
private Map<Bundle, Collection<PermissionDescripton>> bundle2PermissionDescriptorsMap =
Collections.synchronizedMap(new HashMap<Bundle, Collection<PermissionDescripton>>());
private ComponentContext componentContext;
/**
* stores all
* <code>ServiceReference</code>s of
* <code>PermissionDescriptionsProvider</code>s that were bound before the
* PermissionGatherer was activated.
*/
private Set<ServiceReference> serviceReferenceStore = new HashSet<ServiceReference>();
public Map<Bundle, Collection<PermissionDescripton>> getPermissionDescriptorsPerBundles() {
return Collections.unmodifiableMap(bundle2PermissionDescriptorsMap);
}
public Iterator<PermissionDescripton> getAllPermissionDescriptors() {
return new IteratorMerger<PermissionDescripton>(bundle2PermissionDescriptorsMap.values());
}
public Map<Bundle, Collection<Class<? extends Permission>>> getPermissionsPerBundles() {
return Collections.unmodifiableMap(bundle2PermissionClassesMap);
}
public Iterator<Class<? extends Permission>> getAllPermissions() {
return new IteratorMerger<Class<? extends Permission>>(
bundle2PermissionClassesMap.values());
}
protected void activate(final ComponentContext componentContext) {
this.componentContext = componentContext;
registerFromServiceReferenceStore();
componentContext.getBundleContext().addBundleListener(this);
logger.debug("Start registering permissions from activated bundles");
registerPermissionsFromActivatedBundles(componentContext);
logger.debug("Registered permissions from activated bundles");
}
synchronized private void registerFromServiceReferenceStore() {
if (componentContext != null) {
for (ServiceReference ref : serviceReferenceStore) {
this.registerPermissionDescriptorsProvider(ref);
}
serviceReferenceStore.clear();
}
}
synchronized protected void bindPermissionProvider(ServiceReference serviceReference) {
if (componentContext != null) {
registerPermissionDescriptorsProvider(serviceReference);
} else {
serviceReferenceStore.add(serviceReference);
}
}
synchronized protected void unbindPermissionProvider(ServiceReference serviceReference) {
if (!serviceReferenceStore.remove(serviceReference)) {
PermissionDescriptionsProvider permissionProvider = (PermissionDescriptionsProvider) componentContext.locateService("permissionProvider", serviceReference);
Bundle bundle = serviceReference.getBundle();
Collection<PermissionDescripton> permissionDescriptiors =
bundle2PermissionDescriptorsMap.get(bundle);
if (permissionDescriptiors != null) {
permissionDescriptiors.removeAll(permissionProvider.getPermissionDescriptors());
if (permissionDescriptiors.isEmpty()) {
bundle2PermissionDescriptorsMap.remove(bundle);
}
}
}
}
private void registerPermissionDescriptorsProvider(ServiceReference serviceReference) {
PermissionDescriptionsProvider permissionProvider = (PermissionDescriptionsProvider) componentContext.locateService("permissionProvider", serviceReference);
if (permissionProvider == null) {
return;
}
Bundle bundle = serviceReference.getBundle();
Collection<PermissionDescripton> permissionDescriptiors =
bundle2PermissionDescriptorsMap.get(bundle);
if (permissionDescriptiors == null) {
permissionDescriptiors = new HashSet<PermissionDescripton>();
}
permissionDescriptiors.addAll(permissionProvider.getPermissionDescriptors());
bundle2PermissionDescriptorsMap.put(bundle, permissionDescriptiors);
}
protected void deactivate(final ComponentContext componentContext) {
componentContext.getBundleContext().removeBundleListener(this);
bundle2PermissionClassesMap.clear();
bundle2PermissionDescriptorsMap.clear();
}
@Override
public void bundleChanged(BundleEvent event) {
Bundle bundle = event.getBundle();
switch (event.getType()) {
case BundleEvent.STARTED:
registerPermissions(bundle);
break;
case BundleEvent.STOPPED:
unregisterPermissions(bundle);
break;
}
}
private void registerPermissionsFromActivatedBundles(ComponentContext componentContext) {
Bundle[] bundles = componentContext.getBundleContext().getBundles();
for (Bundle bundle : bundles) {
if (bundle.getState() == Bundle.ACTIVE) {
registerPermissions(bundle);
}
}
}
private void registerPermissions(Bundle bundle) {
Enumeration<URL> classUrls = bundle.findEntries("/", "*.class", true);
if (classUrls == null) {
return;
}
Set<Class<? extends Permission>> permissionClassesSet = new HashSet<Class<? extends Permission>>();
Set<PermissionDescripton> newPermissionDescriptors =
new HashSet<PermissionDescripton>();
while (classUrls.hasMoreElements()) {
URL url = classUrls.nextElement();
String className = url.getPath();
int indexOfLastDot = className.lastIndexOf(".");
className = className.replaceAll("/", ".").substring(1, indexOfLastDot);
Class<?> clazz;
try {
clazz = bundle.loadClass(className);
} catch (Throwable t) {
//we just ignore classes we coudln't read
continue;
}
if (Permission.class.isAssignableFrom(clazz)) {
PermissionInfo permissionInfo = clazz.getAnnotation(PermissionInfo.class);
if (permissionInfo != null) {
newPermissionDescriptors.add(new PermissionDescripton(permissionInfo.value(),
permissionInfo.description(), clazz.getResource(permissionInfo.icon()),
(Class<? extends Permission>) clazz,
getJavaPermissionString(clazz)));
} else {
permissionClassesSet.add((Class<? extends Permission>) clazz);
}
}
}
if (!permissionClassesSet.isEmpty()) {
bundle2PermissionClassesMap.put(bundle, permissionClassesSet);
}
if (!newPermissionDescriptors.isEmpty()) {
Collection<PermissionDescripton> permissionDescriptiors =
bundle2PermissionDescriptorsMap.get(bundle);
if (permissionDescriptiors == null) {
permissionDescriptiors = newPermissionDescriptors;
} else {
permissionDescriptiors.addAll(newPermissionDescriptors);
}
bundle2PermissionDescriptorsMap.put(bundle, permissionDescriptiors);
}
}
private void unregisterPermissions(Bundle bundle) {
bundle2PermissionClassesMap.remove(bundle);
bundle2PermissionDescriptorsMap.remove(bundle);
}
private String getJavaPermissionString(Class clazz) {
return "(" + clazz.getName() + " \"\" \"\")";
}
}