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