/* * Licensed 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.aries.subsystem.util.felix; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.aries.subsystem.obr.internal.ResourceHelper; import org.osgi.framework.Constants; import org.osgi.framework.namespace.IdentityNamespace; import org.osgi.resource.Capability; import org.osgi.resource.Requirement; import org.osgi.resource.Resource; import org.osgi.service.repository.Repository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FelixRepositoryAdapter implements Repository { private static class IdentityRequirementFilter { private static final String REGEX = "\\(osgi.identity=([^\\)]*)\\)"; private static final Pattern PATTERN = Pattern.compile(REGEX); private final String symbolicName; public IdentityRequirementFilter(String filter) { Matcher matcher = PATTERN.matcher(filter); if (!matcher.find()) throw new IllegalArgumentException("Could not find pattern '" + REGEX + "' in filter string '" + filter + "'"); symbolicName = matcher.group(1); } public String getSymbolicName() { return symbolicName; } } private static final Logger logger = LoggerFactory.getLogger(FelixRepositoryAdapter.class); private final Map<String, Collection<Capability>> identityIndex = Collections.synchronizedMap(new HashMap<String, Collection<Capability>>()); private final org.apache.felix.bundlerepository.Repository repository; private long lastUpdated; public FelixRepositoryAdapter(org.apache.felix.bundlerepository.Repository repository) { if (repository == null) throw new NullPointerException("Missing required parameter: repository"); this.repository = repository; } public Collection<Capability> findProviders(Requirement requirement) { update(); List<Capability> result = Collections.emptyList(); if (IdentityNamespace.IDENTITY_NAMESPACE.equals(requirement.getNamespace())) { String symbolicName = new IdentityRequirementFilter(requirement.getDirectives().get(Constants.FILTER_DIRECTIVE)).getSymbolicName(); logger.debug("Looking for symbolic name {}", symbolicName); Collection<Capability> capabilities = identityIndex.get(symbolicName); if (capabilities != null) { result = new ArrayList<Capability>(capabilities.size()); for (Capability capability : capabilities) { if (ResourceHelper.matches(requirement, capability)) { result.add(capability); } } ((ArrayList<Capability>)result).trimToSize(); } } else { org.apache.felix.bundlerepository.Resource[] resources = repository.getResources(); if (resources != null && resources.length != 0) { result = new ArrayList<Capability>(resources.length); for (final org.apache.felix.bundlerepository.Resource resource : resources) { Resource r = new FelixResourceAdapter(resource); for (Capability capability : r.getCapabilities(requirement.getNamespace())) if (ResourceHelper.matches(requirement, capability)) result.add(capability); } ((ArrayList<Capability>)result).trimToSize(); } } return result; } @Override public Map<Requirement, Collection<Capability>> findProviders(Collection<? extends Requirement> requirements) { Map<Requirement, Collection<Capability>> result = new HashMap<Requirement, Collection<Capability>>(requirements.size()); for (Requirement requirement : requirements) result.put(requirement, findProviders(requirement)); return result; } private synchronized void update() { long lastModified = repository.getLastModified(); logger.debug("The repository adaptor was last updated at {}. The repository was last modified at {}", lastUpdated, lastModified); if (lastModified > lastUpdated) { logger.debug("Updating the adapter with the modified repository contents..."); lastUpdated = lastModified; synchronized (identityIndex) { identityIndex.clear(); org.apache.felix.bundlerepository.Resource[] resources = repository.getResources(); logger.debug("There are {} resources to evaluate", resources == null ? 0 : resources.length); if (resources != null && resources.length != 0) { for (org.apache.felix.bundlerepository.Resource resource : resources) { logger.debug("Evaluating resource {}", resource); String symbolicName = resource.getSymbolicName(); Collection<Capability> capabilities = identityIndex.get(symbolicName); if (capabilities == null) { capabilities = new HashSet<Capability>(); identityIndex.put(symbolicName, capabilities); } OsgiIdentityCapability capability = new OsgiIdentityCapability( new FelixResourceAdapter(resource), symbolicName, resource.getVersion(), // TODO Assuming all resources are bundles. Need to support // type fragment as well, but how do we know? IdentityNamespace.TYPE_BUNDLE); logger.debug("Indexing capability {}", capability); capabilities.add(capability); } } } } } }