blob: 0237aa465ef2f17b54e4e610aa618f01b9233c57 [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.net.MalformedURLException;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.apache.felix.bundlerepository.Capability;
import org.apache.felix.bundlerepository.DataModelHelper;
import org.apache.felix.bundlerepository.Requirement;
import org.apache.felix.bundlerepository.Repository;
import org.apache.felix.bundlerepository.Resolver;
import org.apache.felix.bundlerepository.Resource;
import org.apache.felix.utils.collections.MapToDictionary;
import org.apache.felix.utils.log.Logger;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Filter;
import org.osgi.framework.InvalidSyntaxException;
import org.apache.felix.bundlerepository.Repository;
import org.apache.felix.bundlerepository.RepositoryAdmin;
public class RepositoryAdminImpl implements RepositoryAdmin
{
private final BundleContext m_context;
private final Logger m_logger;
private final SystemRepositoryImpl m_system;
private final LocalRepositoryImpl m_local;
private final DataModelHelper m_helper = new DataModelHelperImpl();
private Map m_repoMap = new HashMap();
private boolean m_initialized = false;
// Reusable comparator for sorting resources by name.
private Comparator m_nameComparator = new ResourceComparator();
public static final String REPOSITORY_URL_PROP = "obr.repository.url";
public static final String EXTERN_REPOSITORY_TAG = "extern-repositories";
public RepositoryAdminImpl(BundleContext context, Logger logger)
{
m_context = context;
m_logger = logger;
m_system = new SystemRepositoryImpl(context, logger);
m_local = new LocalRepositoryImpl(context, logger);
}
public DataModelHelper getHelper()
{
return m_helper;
}
public Repository getLocalRepository()
{
return m_local;
}
public Repository getSystemRepository()
{
return m_system;
}
public void dispose()
{
m_local.dispose();
}
public Repository addRepository(String uri) throws Exception
{
return addRepository(new URL(uri));
}
public Repository addRepository(URL url) throws Exception
{
return addRepository(url, Integer.MAX_VALUE);
}
public synchronized RepositoryImpl addRepository(final URL url, int hopCount) throws Exception
{
initialize();
// If the repository URL is a duplicate, then we will just
// replace the existing repository object with a new one,
// which is effectively the same as refreshing the repository.
try
{
RepositoryImpl repository = (RepositoryImpl) AccessController.doPrivileged(new PrivilegedExceptionAction()
{
public Object run() throws Exception
{
return m_helper.repository(url);
}
});
m_repoMap.put(url.toExternalForm(), repository);
// resolve referrals
hopCount--;
if (hopCount > 0 && repository.getReferrals() != null)
{
for (int i = 0; i < repository.getReferrals().length; i++)
{
Referral referral = repository.getReferrals()[i];
URL referralUrl = new URL(url, referral.getUrl());
hopCount = (referral.getDepth() > hopCount) ? hopCount : referral.getDepth();
addRepository(referralUrl, hopCount);
}
}
return repository;
}
catch (PrivilegedActionException ex)
{
throw (Exception) ex.getCause();
}
}
public synchronized boolean removeRepository(String uri)
{
initialize();
try
{
URL url = new URL(uri);
return m_repoMap.remove(url.toExternalForm()) != null;
}
catch (MalformedURLException e)
{
return m_repoMap.remove(uri) != null;
}
}
public synchronized Repository[] listRepositories()
{
initialize();
return (Repository[]) m_repoMap.values().toArray(new Repository[m_repoMap.size()]);
}
public synchronized Resolver resolver()
{
initialize();
List repositories = new ArrayList();
repositories.add(m_system);
repositories.add(m_local);
repositories.addAll(m_repoMap.values());
return resolver((Repository[]) repositories.toArray(new Repository[repositories.size()]));
}
public synchronized Resolver resolver(Repository[] repositories)
{
initialize();
if (repositories == null)
{
return resolver();
}
return new ResolverImpl(m_context, repositories, m_logger);
}
public synchronized Resource[] discoverResources(String filterExpr) throws InvalidSyntaxException
{
initialize();
Filter filter = filterExpr != null ? m_helper.filter(filterExpr) : null;
Resource[] resources;
MapToDictionary dict = new MapToDictionary(null);
Repository[] repos = listRepositories();
List matchList = new ArrayList();
for (int repoIdx = 0; (repos != null) && (repoIdx < repos.length); repoIdx++)
{
resources = repos[repoIdx].getResources();
for (int resIdx = 0; (resources != null) && (resIdx < resources.length); resIdx++)
{
dict.setSourceMap(resources[resIdx].getProperties());
if (filter == null || filter.match(dict))
{
matchList.add(resources[resIdx]);
}
}
}
// Convert matching resources to an array an sort them by name.
resources = (Resource[]) matchList.toArray(new Resource[matchList.size()]);
Arrays.sort(resources, m_nameComparator);
return resources;
}
public synchronized Resource[] discoverResources(Requirement[] requirements)
{
initialize();
Resource[] resources = null;
Repository[] repos = listRepositories();
List matchList = new ArrayList();
for (int repoIdx = 0; (repos != null) && (repoIdx < repos.length); repoIdx++)
{
resources = repos[repoIdx].getResources();
for (int resIdx = 0; (resources != null) && (resIdx < resources.length); resIdx++)
{
boolean match = true;
for (int reqIdx = 0; (requirements != null) && (reqIdx < requirements.length); reqIdx++)
{
boolean reqMatch = false;
Capability[] caps = resources[resIdx].getCapabilities();
for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
{
if (requirements[reqIdx].isSatisfied(caps[capIdx]))
{
reqMatch = true;
break;
}
}
match &= reqMatch;
if (!match)
{
break;
}
}
if (match)
{
matchList.add(resources[resIdx]);
}
}
}
// Convert matching resources to an array an sort them by name.
resources = (Resource[]) matchList.toArray(new Resource[matchList.size()]);
Arrays.sort(resources, m_nameComparator);
return resources;
}
private void initialize()
{
if (m_initialized)
{
return;
}
m_initialized = true;
// First check the repository URL config property.
String urlStr = m_context.getProperty(REPOSITORY_URL_PROP);
if (urlStr != null)
{
StringTokenizer st = new StringTokenizer(urlStr);
if (st.countTokens() > 0)
{
while (st.hasMoreTokens())
{
final String token = st.nextToken();
try
{
addRepository(token);
}
catch (Exception ex)
{
m_logger.log(
Logger.LOG_WARNING,
"Repository url " + token + " cannot be used. Skipped.",
ex);
}
}
}
}
}
}