blob: ea992f9b8cb8405a0d1cb4fc23025bf4c676a030 [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.felix.bundlerepository.impl;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.felix.bundlerepository.RepositoryAdmin;
import org.apache.felix.bundlerepository.Resource;
import org.apache.felix.utils.resource.CapabilityImpl;
import org.osgi.framework.Filter;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.namespace.IdentityNamespace;
import org.osgi.resource.Capability;
import org.osgi.resource.Namespace;
import org.osgi.resource.Requirement;
import org.osgi.service.repository.ContentNamespace;
import org.osgi.service.repository.Repository;
class OSGiRepositoryImpl implements Repository
{
private final RepositoryAdmin repository;
OSGiRepositoryImpl(RepositoryAdmin repository)
{
this.repository = repository;
}
public Map<Requirement, Collection<Capability>> findProviders(Collection<? extends Requirement> requirements)
{
Map<Requirement, Collection<Capability>> m = new HashMap<Requirement, Collection<Capability>>();
for (Requirement r : requirements)
{
m.put(r, findProviders(r));
}
return m;
}
private Collection<Capability> findProviders(Requirement req)
{
List<Capability> caps = new ArrayList<Capability>();
if (IdentityNamespace.IDENTITY_NAMESPACE.equals(req.getNamespace()))
{
for(org.apache.felix.bundlerepository.Repository repo : repository.listRepositories())
{
for (org.apache.felix.bundlerepository.Resource res : repo.getResources())
{
String f = req.getDirectives().get(Namespace.REQUIREMENT_FILTER_DIRECTIVE);
try
{
addResourceForIdentity(res,
f == null ? null : FrameworkUtil.createFilter(f), caps);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
}
}
else
{
org.apache.felix.bundlerepository.Resource[] resources = repository.discoverResources(
new org.apache.felix.bundlerepository.Requirement[] {new OSGiRequirementAdapter(req)});
OSGiRequirementAdapter adapter = new OSGiRequirementAdapter(req);
for (org.apache.felix.bundlerepository.Resource resource : resources)
{
for (org.apache.felix.bundlerepository.Capability cap : resource.getCapabilities())
{
if (adapter.isSatisfied(cap))
caps.add(new FelixCapabilityAdapter(cap, new FelixResourceAdapter(resource)));
}
}
}
return caps;
}
private void addResourceForIdentity(final org.apache.felix.bundlerepository.Resource res, Filter filter, List<Capability> caps)
throws Exception
{
List<Capability> idCaps = new FelixResourceAdapter(res).getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE);
if (idCaps.size() == 0)
return;
Capability idCap = idCaps.get(0); // there should only be one osgi.identity anyway
if (filter != null)
{
if (!filter.matches(idCap.getAttributes()))
return;
}
caps.add(idCap);
}
static CapabilityImpl newOSGiIdentityCapability(org.osgi.resource.Resource or, org.apache.felix.bundlerepository.Resource res)
{
@SuppressWarnings("unchecked")
Map<String, Object> idAttrs = new HashMap<String, Object>(res.getProperties());
// Set a number of specific properties that need to be translated
idAttrs.put(IdentityNamespace.IDENTITY_NAMESPACE, res.getSymbolicName());
if (idAttrs.get(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE) == null)
idAttrs.put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, IdentityNamespace.TYPE_BUNDLE);
return new CapabilityImpl(or, IdentityNamespace.IDENTITY_NAMESPACE, Collections.<String, String> emptyMap(), idAttrs);
}
static CapabilityImpl newOSGiContentCapability(org.osgi.resource.Resource or, Resource resource)
{
final String uri = resource.getURI();
LazyStringMap.LazyValue<String> content = new LazyStringMap.LazyValue<String>() {
public String compute() {
// This is expensive to do, so only compute it when actually obtained...
try {
return OSGiRepositoryImpl.getSHA256(uri);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
};
Object mime = resource.getProperties().get("mime");
if (mime == null)
mime = "application/vnd.osgi.bundle";
Map<String, Object> contentAttrs = new LazyStringMap<Object>(4);
contentAttrs.put(ContentNamespace.CAPABILITY_MIME_ATTRIBUTE, mime);
contentAttrs.put(ContentNamespace.CAPABILITY_SIZE_ATTRIBUTE, resource.getSize());
contentAttrs.put(ContentNamespace.CAPABILITY_URL_ATTRIBUTE, uri);
contentAttrs.put(ContentNamespace.CONTENT_NAMESPACE, content);
return new CapabilityImpl(or, ContentNamespace.CONTENT_NAMESPACE, Collections.<String, String> emptyMap(), contentAttrs);
}
static String getSHA256(String uri) throws IOException, NoSuchAlgorithmException // TODO find a good place for this
{
InputStream is = new URL(uri).openStream();
MessageDigest md = MessageDigest.getInstance("SHA-256");
// Use a digest inputstream as using byte arrays directly to compute the SHA-256 can
// have big effects on memory consumption. I.e. you don't want to have to read the
// entire resource in memory. We rather stream it through...
DigestInputStream dis = new DigestInputStream(is, md);
byte[] buffer = new byte[16384];
while (dis.read(buffer) != -1) {
// we just drain the stream here to compute the Message Digest
}
StringBuilder sb = new StringBuilder(64); // SHA-256 is always 64 hex characters
for (byte b : md.digest())
{
sb.append(String.format("%02x", b));
}
return sb.toString();
}
}