| /******************************************************************************* |
| * Copyright (c) 2004 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-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.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) { |
| boolean defaultLocale = false; |
| if (localeString == "") { //$NON-NLS-1$ |
| return (rawHeaders); |
| } |
| if (localeString.equals(Locale.getDefault().toString())) { |
| if (defaultLocaleHeaders != null) { |
| return (defaultLocaleHeaders); |
| } else { |
| defaultLocale = true; |
| } |
| } |
| try { |
| bundle.checkValid(); |
| } catch (IllegalStateException ex) { |
| return (rawHeaders); |
| } |
| ResourceBundle localeProperties = null; |
| localeProperties = getResourceBundle(localeString); |
| if (localeProperties == null) { |
| return rawHeaders; |
| } |
| 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 { |
| String transValue = (String) localeProperties.getObject(propertiesKey); |
| value = transValue; |
| } catch (MissingResourceException ex) { |
| // Do nothing; just use the raw value |
| } |
| } |
| localeHeaders.set(key, value); |
| } |
| if (defaultLocale) { |
| 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 = (BundleResourceBundle) cache.get(nlVarients[i]); |
| URL varientURL = findResource(propertiesLocation + (nlVarients[i].equals("") ? nlVarients[i] : '_' + nlVarients[i]) + ".properties"); //$NON-NLS-1$ //$NON-NLS-2$ |
| if (varientURL != null) { |
| 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) { |
| if (bundle.isResolved()) { |
| AbstractBundle bundleHost; |
| if (bundle.isFragment()) { |
| //if the bundle is a fragment, look in the host first |
| bundleHost = (AbstractBundle) bundle.getHost(); |
| } else { |
| //if the bundle is not a fragment, look in the bundle itself, |
| //then the attached fragments |
| bundleHost = bundle; |
| } |
| return findInResolved(resource, bundleHost); |
| } else { |
| return findInBundle(resource, bundle); |
| } |
| } |
| |
| 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++) { |
| 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(); |
| } |
| } |
| } |