/*
* 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.karaf.bundle.core.internal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
public class BundleSelectorImpl {
private final BundleContext bundleContext;
public BundleSelectorImpl(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
public List<Bundle> selectBundles(List<String> ids, boolean defaultAllBundles) {
List<Bundle> bundles = new ArrayList<>();
if (ids != null && !ids.isEmpty()) {
for (String id : ids) {
if (id == null) {
continue;
}
addMatchingBundles(id, bundles);
}
} else if (defaultAllBundles) {
Collections.addAll(bundles, bundleContext.getBundles());
}
List<Bundle> filteredBundleList = new ArrayList<>(new LinkedHashSet<>(bundles));
return filteredBundleList;
}
private void addMatchingBundles(String id, List<Bundle> bundles) {
// id is a number
Pattern pattern = Pattern.compile("^\\d+$");
Matcher matcher = pattern.matcher(id);
if (matcher.matches()) {
Bundle bundle = this.getBundleById(id);
addBundle(bundle, id, bundles);
return;
}
// id as a number range
pattern = Pattern.compile("^(\\d+)-(\\d+)$");
matcher = pattern.matcher(id);
if (matcher.matches()) {
int index = id.indexOf('-');
long startId = Long.parseLong(id.substring(0, index));
long endId = Long.parseLong(id.substring(index + 1));
if (startId < endId) {
for (long i = startId; i <= endId; i++) {
Bundle bundle = bundleContext.getBundle(i);
addBundle(bundle, String.valueOf(i), bundles);
}
}
return;
}
// bundles by name
int index = id.indexOf('/');
List<Bundle> bundlesByName;
if (index != -1) {
// user has provided name and version
bundlesByName = getBundleByNameAndVersion(id.substring(0, index), id.substring(index + 1));
} else {
// user has provided only the name
bundlesByName = getBundleByName(id);
}
for (Bundle bundleByName : bundlesByName) {
addBundle(bundleByName, id, bundles);
}
// bundles by location
List<Bundle> bundlesByLocation = getBundlesByLocation(id);
for (Bundle bundleByLocation : bundlesByLocation) {
addBundle(bundleByLocation, id, bundles);
}
}
private void addBundle(Bundle bundle, String id, List<Bundle> bundles) {
if (bundle == null) {
// if the bundle is null here, it's because we didn't find it
System.err.println("Bundle " + id + " is invalid");
} else {
bundles.add(bundle);
}
}
/**
* Get a bundle identified by an id number.
*
* @param id the id number.
* @return the bundle or null if not found.
*/
private Bundle getBundleById(String id) {
Bundle bundle = null;
try {
long idNumber = Long.parseLong(id);
bundle = bundleContext.getBundle(idNumber);
} catch (NumberFormatException nfe) {
// ignore
}
return bundle;
}
/**
* Get a bundles list with the name or symbolic name matching the pattern.
*
* @param name the bundle name or symbolic name pattern to match.
* @return the bundles list.
*/
private List<Bundle> getBundleByName(String name) {
return getBundleByNameAndVersion(name, null);
}
/**
* Get a bundles list with the name or symbolic name matching the name pattern and version matching the version pattern.
*
* @param name the bundle name or symbolic name regex to match.
* @param version the bundle version regex to match.
* @return the bundles list.
*/
private List<Bundle> getBundleByNameAndVersion(String name, String version) {
Bundle[] bundles = bundleContext.getBundles();
ArrayList<Bundle> result = new ArrayList<>();
Pattern namePattern = Pattern.compile(name);
for (Bundle bundle : bundles) {
String bundleSymbolicName = bundle.getSymbolicName();
// skip bundles without Bundle-SymbolicName header
if (bundleSymbolicName == null) {
continue;
}
Matcher symbolicNameMatcher = namePattern.matcher(bundleSymbolicName);
Matcher nameMatcher = null;
String bundleName = bundle.getHeaders().get(Constants.BUNDLE_NAME);
if (bundleName != null) {
nameMatcher = namePattern.matcher(bundleName);
}
if (version != null) {
String bundleVersion = bundle.getHeaders().get(Constants.BUNDLE_VERSION);
if (bundleVersion != null) {
boolean nameMatch = (nameMatcher != null && nameMatcher.matches()) || symbolicNameMatcher.matches();
if (nameMatch) {
Pattern versionPattern = Pattern.compile(version);
Matcher versionMatcher = versionPattern.matcher(bundleVersion);
if (versionMatcher.matches()) {
result.add(bundle);
}
}
}
} else {
boolean nameMatch = (nameMatcher != null && nameMatcher.matches()) || symbolicNameMatcher.matches();
if (nameMatch) {
result.add(bundle);
}
}
}
return result;
}
private List<Bundle> getBundlesByLocation(String url) {
Bundle[] bundles = bundleContext.getBundles();
ArrayList<Bundle> result = new ArrayList<>();
Pattern locationPattern = Pattern.compile(url);
for (Bundle bundle : bundles) {
Matcher locationMatcher = locationPattern.matcher(bundle.getLocation());
if (locationMatcher.matches()) {
result.add(bundle);
}
}
return result;
}
}