| /* |
| * 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.netbeans.updater; |
| |
| import java.util.*; |
| import java.io.*; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.net.URLClassLoader; |
| |
| class Localization { |
| |
| private static final String FILE_SEPARATOR = System.getProperty ("file.separator"); // NOI18N |
| private static final String LOCALE_DIR = "modules" + FILE_SEPARATOR + "ext" + FILE_SEPARATOR + "locale"; // NOI18N |
| private static final String BUNDLE_NAME = "org/netbeans/updater/Bundle"; // NOI18N |
| private static final String BUNDLE_EXT = ".properties"; // NOI18N |
| private static final String UPDATER_JAR = "updater"; // NOI18N |
| private static final String UPDATER_JAR_EXT = ".jar"; // NOI18N |
| |
| private static ClassLoader brandedLoader = null; |
| |
| private static String brandingToken = null; |
| |
| private static Map<String, ResourceBundle> bundleCache = new HashMap<String, ResourceBundle>(); // XXX: this is leaking cache |
| |
| public static String getBranding() { |
| if (brandingToken != null) { |
| init(); |
| } |
| return brandingToken; |
| } |
| |
| public static String getBrandedString( String key ) { |
| init(); // When not initialized do so |
| |
| // Let's try to find a bundle |
| for( LocaleIterator li = new LocaleIterator( Locale.getDefault() ); li.hasNext(); ) { |
| try { |
| ResourceBundle bundle = findBrandedBundle( (String)li.next() ); |
| |
| if ( bundle != null ) { |
| // So we have the bundle, now we need the string |
| String brandedString = bundle.getString( key ); |
| if ( brandedString != null ) { |
| return brandedString; // We even found the string |
| } |
| // Continue |
| } |
| } |
| catch ( java.util.MissingResourceException e ) { |
| // No string, no problem, let's try other one |
| } |
| } |
| return null; |
| } |
| |
| private static ResourceBundle findBrandedBundle( String loc ) { |
| |
| ResourceBundle bundle = bundleCache.get( loc ); // Maybe is in cache |
| if ( bundle != null ) { |
| return bundle; |
| } |
| |
| // Was not in cache |
| |
| |
| InputStream is = brandedLoader.getResourceAsStream( BUNDLE_NAME + loc + BUNDLE_EXT ); |
| if (is != null) { |
| try { |
| try { |
| Properties p = new Properties(); |
| p.load(is); |
| bundle= new PBundle( p, new Locale( "" ) ); |
| bundleCache.put( loc, bundle ); |
| return bundle; |
| } finally { |
| is.close(); |
| } |
| } catch (IOException e) { |
| return null; |
| } |
| } |
| |
| return null; |
| } |
| |
| |
| public static URL getBrandedResource( String base, String ext ) { |
| init(); // When not initialized do so |
| |
| // Let's try all the possibilities |
| for( LocaleIterator li = new LocaleIterator( Locale.getDefault() ); li.hasNext(); ) { |
| URL url = brandedLoader.getResource( base + li.next() + ext ); |
| if ( url != null ) { |
| return url; |
| } |
| } |
| |
| return null; |
| } |
| |
| |
| public static InputStream getBrandedResourceAsStream( String base, String ext ) { |
| init(); // When not initialized do so |
| |
| // Let's try all the possibilities |
| for( LocaleIterator li = new LocaleIterator( Locale.getDefault() ); li.hasNext(); ) { |
| InputStream is = brandedLoader.getResourceAsStream( base + li.next() + ext ); |
| if ( is != null ) { |
| return is; |
| } |
| } |
| |
| return null; |
| } |
| |
| public static void setBranding (String branding) { |
| brandingToken = branding; |
| } |
| |
| // Private methods --------------------------------------------------------- |
| private static synchronized void init() { |
| if (brandingToken == null) { |
| // Initialize the branding token |
| brandingToken = initBranding(); |
| } |
| if (brandedLoader == null) { |
| |
| // Fallback to default class loader |
| brandedLoader = Localization.class.getClassLoader(); |
| |
| // Try to find some localized jars and store the URLS |
| List<URL> locJarURLs = new ArrayList<URL>(); |
| |
| for( LocaleIterator li = new LocaleIterator( Locale.getDefault() ); li.hasNext(); ) { |
| String localeName = li.next().toString (); |
| // loop for clusters |
| Iterator it = UpdateTracking.clusters (true).iterator (); |
| while (it.hasNext ()) { |
| File cluster = (File)it.next (); |
| File locJar = new File( cluster.getPath () + FILE_SEPARATOR + LOCALE_DIR + FILE_SEPARATOR + UPDATER_JAR + localeName + UPDATER_JAR_EXT ); |
| if ( locJar.exists() ) { // File exists |
| try { |
| locJarURLs.add( locJar.toURI().toURL() ); // Convert to URL |
| } |
| catch ( MalformedURLException e ) { |
| // dont use and ignore |
| } |
| } |
| } |
| } |
| |
| if ( !locJarURLs.isEmpty() ) { // we've found some localization jars |
| // Make an array of URLs |
| URL urls[] = new URL[ locJarURLs.size() ]; |
| locJarURLs.toArray( urls ); |
| |
| // Create the new classLoader |
| brandedLoader = new URLClassLoader( urls, brandedLoader ); |
| } |
| |
| } |
| } |
| |
| /** Returns current branding |
| */ |
| private static String initBranding() { |
| BufferedReader in = null; |
| String s = null; |
| try { |
| if (UpdateTracking.getPlatformDir () == null) { |
| return s; |
| } |
| File brandf = new File (UpdateTracking.getPlatformDir(), |
| "lib" + FILE_SEPARATOR + "branding"); // NOI18N |
| in = new BufferedReader(new FileReader(brandf)); |
| if (in.ready()) { |
| XMLUtil.LOG.warning("It's obsolete. Use --branding <branding> instead 'branding' file."); |
| s = in.readLine(); |
| } |
| } |
| catch (IOException e) { |
| } |
| finally { |
| if (in != null) try { in.close(); } catch (IOException e) { /* ignore */ }; |
| } |
| return s; |
| } |
| |
| /** |
| * ============================================================================= |
| * N O T I C E |
| * ----------------------------------------------------------------------------- |
| * This class was copyied from NbBundle. The reason is that the updater must not |
| * use any NetBeans class in order to be able to update them. |
| * ----------------------------------------------------------------------------- |
| * |
| * This class (enumeration) gives all localized sufixes using nextElement |
| * method. It goes through given Locale and continues through Locale.getDefault() |
| * Example 1: |
| * Locale.getDefault().toString() -> "_en_US" |
| * you call new LocaleIterator(new Locale("cs", "CZ")); |
| * ==> You will gets: "_cs_CZ", "_cs", "", "_en_US", "_en" |
| * |
| * Example 2: |
| * Locale.getDefault().toString() -> "_cs_CZ" |
| * you call new LocaleIterator(new Locale("cs", "CZ")); |
| * ==> You will gets: "_cs_CZ", "_cs", "" |
| * |
| * If there is a branding token in effect, you will get it too as an extra |
| * prefix, taking precedence, e.g. for the token "f4jce": |
| * |
| * "_f4jce_cs_CZ", "_f4jce_cs", "_f4jce", "_f4jce_en_US", "_f4jce_en", "_cs_CZ", "_cs", "", "_en_US", "_en" |
| * |
| * Branding tokens with underscores are broken apart naturally: so e.g. |
| * branding "f4j_ce" looks first for "f4j_ce" branding, then "f4j" branding, then none. |
| */ |
| private static class LocaleIterator extends Object implements Iterator { |
| /** this flag means, if default locale is in progress */ |
| private boolean defaultInProgress = false; |
| |
| /** this flag means, if empty sufix was exported yet */ |
| private boolean empty = false; |
| |
| /** current locale, and initial locale */ |
| private Locale locale, initLocale; |
| |
| /** current sufix which will be returned in next calling nextElement */ |
| private String current; |
| |
| /** the branding string in use */ |
| private String branding; |
| |
| /** Creates new LocaleIterator for given locale. |
| * @param locale given Locale |
| */ |
| public LocaleIterator (Locale locale) { |
| this.locale = this.initLocale = locale; |
| if (locale.equals(Locale.getDefault())) { |
| defaultInProgress = true; |
| } |
| current = '_' + locale.toString(); |
| if (brandingToken == null) |
| branding = null; |
| else |
| branding = "_" + brandingToken; // NOI18N |
| //System.err.println("Constructed: " + this); |
| } |
| |
| /** @return next sufix. |
| * @exception NoSuchElementException if there is no more locale sufix. |
| */ |
| public Object next () throws NoSuchElementException { |
| if (current == null) |
| throw new NoSuchElementException(); |
| |
| final String ret; |
| if (branding == null) { |
| ret = current; |
| } else { |
| ret = branding + current; |
| } |
| int lastUnderbar = current.lastIndexOf('_'); |
| if (lastUnderbar == 0) { |
| if (empty) |
| reset (); |
| else { |
| current = ""; // NOI18N |
| empty = true; |
| } |
| } |
| else { |
| if (lastUnderbar == -1) { |
| if (defaultInProgress) |
| reset (); |
| else { |
| // [PENDING] stuff with trying the default locale |
| // after the real one does not actually seem to work... |
| locale = Locale.getDefault(); |
| current = '_' + locale.toString(); |
| defaultInProgress = true; |
| } |
| } |
| else { |
| current = current.substring(0, lastUnderbar); |
| } |
| } |
| //System.err.println("Returning: `" + ret + "' from: " + this); |
| return ret; |
| } |
| |
| /** Finish a series. |
| * If there was a branding prefix, restart without that prefix |
| * (or with a shorter prefix); else finish. |
| */ |
| private void reset () { |
| if (branding != null) { |
| current = '_' + initLocale.toString (); |
| int idx = branding.lastIndexOf ('_'); |
| if (idx == 0) |
| branding = null; |
| else |
| branding = branding.substring (0, idx); |
| empty = false; |
| } else { |
| current = null; |
| } |
| } |
| |
| /** Tests if there is any sufix.*/ |
| public boolean hasNext () { |
| return (current != null); |
| } |
| |
| public void remove () throws UnsupportedOperationException { |
| throw new UnsupportedOperationException (); |
| } |
| |
| } // end of LocaleIterator |
| |
| /** |
| * ============================================================================= |
| * N O T I C E |
| * ----------------------------------------------------------------------------- |
| * YASC - Yet Another Stolen Class |
| * ----------------------------------------------------------------------------- |
| * A resource bundle based on <samp>.properties</samp> files (or any map). |
| */ |
| private static final class PBundle extends ResourceBundle { |
| private final Map<String, String> m; |
| private final Locale locale; |
| /** |
| * Create a new bundle based on a map. |
| * @param m a map from resources keys to values (typically both strings) |
| * @param locale the locale it represents <em>(informational)</em> |
| */ |
| @SuppressWarnings("unchecked") |
| public PBundle(Map m, Locale locale) { |
| this.m = m; |
| this.locale = locale; |
| } |
| public Enumeration<String> getKeys() { |
| return Collections.enumeration(m.keySet()); |
| } |
| protected Object handleGetObject(String key) { |
| return m.get(key); |
| } |
| @Override public Locale getLocale() { |
| return locale; |
| } |
| } |
| |
| } |