| /******************************************************************************* |
| * Copyright (c) 2004, 2007 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.osgi.framework.internal.core; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.URL; |
| import java.util.*; |
| import org.eclipse.osgi.framework.util.Headers; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.Constants; |
| |
| /** |
| * This class is used by the Bundle Class to localize manifest headers. |
| */ |
| public class ManifestLocalization { |
| private AbstractBundle bundle = null; |
| private Dictionary rawHeaders = null; |
| private Dictionary defaultLocaleHeaders = null; |
| private Hashtable cache = new Hashtable(5); |
| |
| public ManifestLocalization(AbstractBundle bundle, Dictionary rawHeaders) { |
| this.bundle = bundle; |
| this.rawHeaders = rawHeaders; |
| } |
| |
| protected Dictionary getHeaders(String localeString) { |
| if (localeString.length() == 0) |
| return (rawHeaders); |
| boolean isDefaultLocale = false; |
| String defaultLocale = Locale.getDefault().toString(); |
| if (localeString.equals(defaultLocale)) { |
| if (defaultLocaleHeaders != null) |
| return (defaultLocaleHeaders); |
| isDefaultLocale = true; |
| } |
| try { |
| bundle.checkValid(); |
| } catch (IllegalStateException ex) { |
| // defaultLocaleHeaders should have been initialized on uninstall |
| if (defaultLocaleHeaders != null) |
| return defaultLocaleHeaders; |
| return (rawHeaders); |
| } |
| ResourceBundle localeProperties = getResourceBundle(localeString); |
| if (localeProperties == null && !isDefaultLocale) |
| // could not find the requested locale use the default locale |
| localeProperties = getResourceBundle(defaultLocale); |
| Enumeration e = this.rawHeaders.keys(); |
| Headers localeHeaders = new Headers(this.rawHeaders.size()); |
| while (e.hasMoreElements()) { |
| String key = (String) e.nextElement(); |
| String value = (String) this.rawHeaders.get(key); |
| if (value.startsWith("%") && (value.length() > 1)) { //$NON-NLS-1$ |
| String propertiesKey = value.substring(1); |
| try { |
| value = localeProperties == null ? propertiesKey : (String) localeProperties.getObject(propertiesKey); |
| } catch (MissingResourceException ex) { |
| value = propertiesKey; |
| } |
| } |
| localeHeaders.set(key, value); |
| } |
| localeHeaders.setReadOnly(); |
| if (isDefaultLocale) { |
| defaultLocaleHeaders = localeHeaders; |
| } |
| return (localeHeaders); |
| } |
| |
| private String[] buildNLVariants(String nl) { |
| ArrayList result = new ArrayList(); |
| int lastSeparator; |
| while ((lastSeparator = nl.lastIndexOf('_')) != -1) { |
| result.add(nl); |
| if (lastSeparator != -1) { |
| nl = nl.substring(0, lastSeparator); |
| } |
| } |
| result.add(nl); |
| // always add the default locale string |
| result.add(""); //$NON-NLS-1$ |
| return (String[]) result.toArray(new String[result.size()]); |
| } |
| |
| /* |
| * This method find the appropiate Manifest Localization file inside the |
| * bundle. If not found, return null. |
| */ |
| protected ResourceBundle getResourceBundle(String localeString) { |
| String propertiesLocation = (String) rawHeaders.get(Constants.BUNDLE_LOCALIZATION); |
| if (propertiesLocation == null) { |
| propertiesLocation = Constants.BUNDLE_LOCALIZATION_DEFAULT_BASENAME; |
| } |
| |
| BundleResourceBundle result = (BundleResourceBundle) cache.get(localeString); |
| if (result != null) |
| return (ResourceBundle) (result.isEmpty() ? null : result); |
| String[] nlVarients = buildNLVariants(localeString); |
| BundleResourceBundle parent = null; |
| for (int i = nlVarients.length - 1; i >= 0; i--) { |
| BundleResourceBundle varientBundle = null; |
| URL varientURL = findResource(propertiesLocation + (nlVarients[i].equals("") ? nlVarients[i] : '_' + nlVarients[i]) + ".properties"); //$NON-NLS-1$ //$NON-NLS-2$ |
| if (varientURL == null) { |
| varientBundle = (BundleResourceBundle) cache.get(nlVarients[i]); |
| } else { |
| InputStream resourceStream = null; |
| try { |
| resourceStream = varientURL.openStream(); |
| varientBundle = new LocalizationResourceBundle(resourceStream); |
| } catch (IOException e) { |
| // ignore and continue |
| } finally { |
| if (resourceStream != null) { |
| try { |
| resourceStream.close(); |
| } catch (IOException e3) { |
| //Ignore exception |
| } |
| } |
| } |
| } |
| |
| if (varientBundle == null) { |
| varientBundle = new EmptyResouceBundle(); |
| } |
| if (parent != null) |
| varientBundle.setParent((ResourceBundle) parent); |
| cache.put(nlVarients[i], varientBundle); |
| parent = varientBundle; |
| } |
| result = (BundleResourceBundle) cache.get(localeString); |
| return (ResourceBundle) (result.isEmpty() ? null : result); |
| } |
| |
| private URL findResource(String resource) { |
| AbstractBundle searchBundle = bundle; |
| if (bundle.isResolved()) { |
| if (bundle.isFragment() && bundle.getHosts() != null) { |
| //if the bundle is a fragment, look in the host first |
| searchBundle = bundle.getHosts()[0].getBundleHost(); |
| if (searchBundle.getState() == Bundle.UNINSTALLED) |
| searchBundle = bundle; |
| } |
| return findInResolved(resource, searchBundle); |
| } |
| return findInBundle(resource, searchBundle); |
| } |
| |
| private URL findInResolved(String filePath, AbstractBundle bundleHost) { |
| |
| URL result = findInBundle(filePath, bundleHost); |
| if (result != null) |
| return result; |
| return findInFragments(filePath, bundleHost); |
| } |
| |
| private URL findInBundle(String filePath, AbstractBundle searchBundle) { |
| return searchBundle.getEntry(filePath); |
| } |
| |
| private URL findInFragments(String filePath, AbstractBundle searchBundle) { |
| org.osgi.framework.Bundle[] fragments = searchBundle.getFragments(); |
| URL fileURL = null; |
| for (int i = 0; fragments != null && i < fragments.length && fileURL == null; i++) { |
| if (fragments[i].getState() != Bundle.UNINSTALLED) |
| fileURL = fragments[i].getEntry(filePath); |
| } |
| return fileURL; |
| } |
| |
| private abstract interface BundleResourceBundle { |
| void setParent(ResourceBundle parent); |
| |
| boolean isEmpty(); |
| } |
| |
| private class LocalizationResourceBundle extends PropertyResourceBundle implements BundleResourceBundle { |
| public LocalizationResourceBundle(InputStream in) throws IOException { |
| super(in); |
| } |
| |
| public void setParent(ResourceBundle parent) { |
| super.setParent(parent); |
| } |
| |
| public boolean isEmpty() { |
| return false; |
| } |
| } |
| |
| private class EmptyResouceBundle extends ResourceBundle implements BundleResourceBundle { |
| public Enumeration getKeys() { |
| return null; |
| } |
| |
| protected Object handleGetObject(String arg0) throws MissingResourceException { |
| return null; |
| } |
| |
| public void setParent(ResourceBundle parent) { |
| super.setParent(parent); |
| } |
| |
| public boolean isEmpty() { |
| if (parent == null) |
| return true; |
| return ((BundleResourceBundle) parent).isEmpty(); |
| } |
| } |
| } |