blob: f26a157af4056e265ecf685ef12fc00190b94a9a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.equinox.internal.provisional.p2.ui.query;
import java.lang.ref.SoftReference;
import java.net.URL;
import java.util.*;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.equinox.internal.p2.core.helpers.LogHelper;
import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper;
import org.eclipse.equinox.internal.p2.metadata.InstallableUnit;
import org.eclipse.equinox.internal.p2.ui.ProvUIActivator;
import org.eclipse.equinox.internal.provisional.p2.engine.IProfile;
import org.eclipse.equinox.internal.provisional.p2.engine.IProfileRegistry;
import org.eclipse.equinox.internal.provisional.p2.metadata.*;
import org.eclipse.equinox.internal.provisional.p2.metadata.query.IUPropertyQuery;
import org.eclipse.equinox.internal.provisional.p2.query.Collector;
public class IUPropertyUtils {
// TODO: these constants should come from API, eg. IInstallableUnit or ???
static final Locale DEFAULT_LOCALE = new Locale("df", "LT"); //$NON-NLS-1$//$NON-NLS-2$
static final String NAMESPACE_IU_LOCALIZATION = "org.eclipse.equinox.p2.localization"; //$NON-NLS-1$
// Cache the IU fragments that provide localizations for a given locale.
// map: locale => soft reference to a collector
private static Map LocaleCollectorCache = new HashMap(2);
// Get the license in the default locale.
public static License getLicense(IInstallableUnit iu) {
return getLicense(iu, getCurrentLocale());
}
// Get the copyright in the default locale.
public static Copyright getCopyright(IInstallableUnit iu) {
return getCopyright(iu, getCurrentLocale());
}
// Get a property in the default locale
public static String getIUProperty(IInstallableUnit iu, String propertyKey) {
return getIUProperty(iu, propertyKey, getCurrentLocale());
}
public static License getLicense(IInstallableUnit iu, Locale locale) {
License license = iu.getLicense();
String body = (license != null ? license.getBody() : null);
if (body == null || body.length() <= 1 || body.charAt(0) != '%')
return license;
final String actualKey = body.substring(1); // Strip off the %
body = getLocalizedIUProperty(iu, actualKey, locale);
URL url = license.getURL();
return new License((url != null ? url.toExternalForm() : null), body);
}
public static Copyright getCopyright(IInstallableUnit iu, Locale locale) {
Copyright copyright = iu.getCopyright();
String body = (copyright != null ? copyright.getBody() : null);
if (body == null || body.length() <= 1 || body.charAt(0) != '%')
return copyright;
final String actualKey = body.substring(1); // Strip off the %
body = getLocalizedIUProperty(iu, actualKey, locale);
URL url = copyright.getURL();
return new Copyright((url != null ? url.toExternalForm() : null), body);
}
public static String getIUProperty(IInstallableUnit iu, String propertyKey, Locale locale) {
String value = iu.getProperty(propertyKey);
if (value == null || value.length() <= 1 || value.charAt(0) != '%')
return value;
// else have a localizable property
final String actualKey = value.substring(1); // Strip off the %
return getLocalizedIUProperty(iu, actualKey, locale);
}
private static String getLocalizedIUProperty(IInstallableUnit iu, String actualKey, Locale locale) {
String localizedKey = makeLocalizedKey(actualKey, locale.toString());
String localizedValue = null;
//first check for a cached localized value
if (iu instanceof InstallableUnit)
localizedValue = ((InstallableUnit) iu).getLocalizedProperty(localizedKey);
//next check if the localized value is stored in the same IU (common case)
if (localizedValue == null)
localizedValue = iu.getProperty(localizedKey);
if (localizedValue != null)
return localizedValue;
final List locales = buildLocaleVariants(locale);
final IInstallableUnit theUnit = iu;
Collector localizationFragments = getLocalizationFragments(locale, locales);
Collector hostLocalizationCollector = new Collector() {
public boolean accept(Object object) {
boolean haveHost = false;
if (object instanceof IInstallableUnitFragment) {
IInstallableUnitFragment fragment = (IInstallableUnitFragment) object;
RequiredCapability[] hosts = fragment.getHost();
for (int i = 0; i < hosts.length; i++) {
RequiredCapability nextHost = hosts[i];
if (IInstallableUnit.NAMESPACE_IU_ID.equals(nextHost.getNamespace()) && //
theUnit.getId().equals(nextHost.getName()) && //
nextHost.getRange() != null && //
nextHost.getRange().isIncluded(theUnit.getVersion())) {
haveHost = true;
break;
}
}
}
return (haveHost ? super.accept(object) : false);
}
};
IUPropertyQuery iuQuery = new IUPropertyQuery(IInstallableUnit.PROP_TYPE_FRAGMENT, "true"); //$NON-NLS-1$
Collector collected = iuQuery.perform(localizationFragments.iterator(), hostLocalizationCollector);
if (!collected.isEmpty()) {
String translation = null;
for (Iterator iter = collected.iterator(); iter.hasNext() && translation == null;) {
IInstallableUnit localizationIU = (IInstallableUnit) iter.next();
for (Iterator jter = locales.iterator(); jter.hasNext();) {
String localeKey = makeLocalizedKey(actualKey, (String) jter.next());
translation = localizationIU.getProperty(localeKey);
if (translation != null)
return cacheResult(iu, localizedKey, translation);
}
}
}
for (Iterator iter = locales.iterator(); iter.hasNext();) {
String nextLocale = (String) iter.next();
String localeKey = makeLocalizedKey(actualKey, nextLocale);
String nextValue = iu.getProperty(localeKey);
if (nextValue != null)
return cacheResult(iu, localizedKey, nextValue);
}
return cacheResult(iu, localizedKey, actualKey);
}
/**
* Cache the translated property value to optimize future retrieval of the same value.
* Currently we just cache on the installable unit object in memory. In future
* we should push support for localized property retrieval into IInstallableUnit
* so we aren't required to reach around the API here.
*/
private static String cacheResult(IInstallableUnit iu, String localizedKey, String localizedValue) {
if (iu instanceof InstallableUnit)
((InstallableUnit) iu).setLocalizedProperty(localizedKey, localizedValue);
return localizedValue;
}
/**
* Collects the installable unit fragments that contain locale data for the given locales.
*/
private static synchronized Collector getLocalizationFragments(Locale locale, List localeVariants) {
SoftReference collectorRef = (SoftReference) LocaleCollectorCache.get(locale);
if (collectorRef != null) {
Collector cached = (Collector) collectorRef.get();
if (cached != null)
return cached;
}
final List locales = localeVariants;
Collector localeFragmentCollector = new Collector() {
public boolean accept(Object object) {
boolean haveLocale = false;
if (object instanceof IInstallableUnitFragment) {
IInstallableUnitFragment fragment = (IInstallableUnitFragment) object;
ProvidedCapability[] provides = fragment.getProvidedCapabilities();
for (int j = 0; j < provides.length && !haveLocale; j++) {
ProvidedCapability nextProvide = provides[j];
if (NAMESPACE_IU_LOCALIZATION.equals(nextProvide.getNamespace())) {
String providedLocale = nextProvide.getName();
if (providedLocale != null) {
for (Iterator iter = locales.iterator(); iter.hasNext();) {
if (providedLocale.equals(iter.next())) {
haveLocale = true;
break;
}
}
}
}
}
}
return (haveLocale ? super.accept(object) : false);
}
};
//Due to performance problems we restrict locale lookup to the current profile (see bug 233958)
IProfileRegistry profileRegistry = (IProfileRegistry) ServiceHelper.getService(ProvUIActivator.getContext(), IProfileRegistry.class.getName());
if (profileRegistry == null) {
LogHelper.log(new Status(IStatus.ERROR, ProvUIActivator.PLUGIN_ID, "Profile registry unavailable. Default language will be used.", new RuntimeException())); //$NON-NLS-1$
return new Collector();
}
IProfile profile = profileRegistry.getProfile(IProfileRegistry.SELF);
if (profile == null) {
LogHelper.log(new Status(IStatus.ERROR, ProvUIActivator.PLUGIN_ID, "Profile unavailable. Default language will be used.", new RuntimeException())); //$NON-NLS-1$
return new Collector();
}
IUPropertyQuery iuQuery = new IUPropertyQuery(IInstallableUnit.PROP_TYPE_FRAGMENT, "true"); //$NON-NLS-1$
Collector collected = profile.query(iuQuery, localeFragmentCollector, null);
LocaleCollectorCache.put(locale, new SoftReference(collected));
return collected;
}
/**
*/
private static List buildLocaleVariants(Locale locale) {
String nl = locale.toString();
ArrayList result = new ArrayList(4);
int lastSeparator;
while (true) {
result.add(nl);
lastSeparator = nl.lastIndexOf('_');
if (lastSeparator == -1)
break;
nl = nl.substring(0, lastSeparator);
}
// Add the default locale (most general)
result.add(DEFAULT_LOCALE.toString());
return result;
}
private static String makeLocalizedKey(String actualKey, String localeImage) {
return localeImage + '.' + actualKey;
}
private static Locale getCurrentLocale() {
return Locale.getDefault();
}
}