/* * 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; } }