/* * Copyright 2012 The Solmix Project * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.gnu.org/licenses/ * or see the FSF site: http://www.fsf.org. */ package org.solmix.fmk.i18n; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URISyntaxException; import java.net.URL; import java.util.Enumeration; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.osgi.framework.Bundle; import org.osgi.framework.Constants; import org.solmix.SlxConstants; import org.solmix.api.exception.SlxException; import org.solmix.api.types.Texception; import org.solmix.api.types.Tmodule; import org.solmix.commons.util.SimpleFilter; import org.solmix.fmk.util.MessageTools; /** * The <code>ResourceBundleCache</code> caches resource bundles per OSGI bundle. * * @author Administrator * @version 110035 2011-3-15 */ @SuppressWarnings("unchecked") public class ResourceBundleCache { private Map<String,Object> resourceBundleEntries; private final Bundle bundle; private final Map<Locale, ResourceBundle> resourceBundles; public ResourceBundleCache() { this(null); } public ResourceBundleCache(Bundle bundle) { this.bundle = bundle; this.resourceBundles = new HashMap<Locale, ResourceBundle>(); } ResourceBundle getResourceBundle(Locale locale) throws SlxException { ResourceBundle rb=null; try { rb= getResourceBundleInternal(locale==null?MessageTools.DEFAULT_LOCALE:locale); if(rb==null) rb=getResourceBundleInternal(MessageTools.DEFAULT_LOCALE); } catch (IOException e) {e.printStackTrace(); throw new SlxException(Tmodule.BASIC,Texception.IO_EXCEPTION,"Exception When load properties"); } return rb; } ResourceBundle getResourceBundleInternal(Locale locale) throws IOException { if (locale == null) { return null; } synchronized (resourceBundles) { ResourceBundle bundle = (ResourceBundle) resourceBundles.get(locale); if (bundle != null) { return bundle; } } ResourceBundle parent = getResourceBundleInternal(getParentLocale(locale)); ResourceBundle bundle = loadResourceBundle(parent, locale); synchronized (resourceBundles) { resourceBundles.put(locale, bundle); } return bundle; } /** * @param parent * @param locale * @return * @throws IOException */ private ResourceBundle loadResourceBundle(ResourceBundle parent, Locale locale) throws IOException { String path = "_" + locale.toString(); final Object source = getResourceBundleEntries().get(path); if(source instanceof URL){ return new PropertyResourceBundle(parent, (URL)source); }else if(source instanceof PropertyResourceBundle){ return (PropertyResourceBundle)source; }else if(source instanceof InputStream){ return new PropertyResourceBundle(parent, (InputStream)source); } return null; } /** * @return * @throws IOException */ private synchronized Map<String,Object> getResourceBundleEntries() throws IOException { Map<String,Object> _resourceBundleEntries = new HashMap<String,Object>(); int start = 0; if (this.resourceBundleEntries == null) { String _file = null; if (SlxConstants.isOSGI() && bundle != null) { _file = (String) bundle.getHeaders().get(Constants.BUNDLE_LOCALIZATION); } if (_file == null) { _file = Constants.BUNDLE_LOCALIZATION_DEFAULT_BASENAME; } if (_file.startsWith("/")) { _file = _file.substring(1); } int slash = _file.lastIndexOf('/'); String fileName = _file.substring(slash + 1); String path = (slash <= 0) ? "/" : _file.substring(0, slash); if (SlxConstants.isOSGI() && bundle != null) { Enumeration locales = bundle.findEntries(path, fileName + "*.properties", false); if (locales != null) { while (locales.hasMoreElements()) { URL entry = (URL) locales.nextElement(); String entryPath = entry.getPath(); start = 1 + _file.length(); final int end = entryPath.length() - 11; entryPath = entryPath.substring(start, end); if (entryPath.length() == 0) { entryPath = "_" + MessageTools.DEFAULT_LOCALE.toString(); } if (!_resourceBundleEntries.containsKey(entryPath)) { _resourceBundleEntries.put(entryPath, entry); } } } } else { _resourceBundleEntries = getLocalEntries( path, fileName + "*.properties", false); } // END (locales != null) this.resourceBundleEntries = _resourceBundleEntries; }// END (this.resourceBundleEntries == null) return this.resourceBundleEntries; } /** * @param path * @param string * @param b * @return * @throws IOException */ protected Map<String,Object> getLocalEntries(String path, String filePattern, boolean b) throws IOException { Object sm = System.getSecurityManager(); if (sm != null) { // TODO deal security }if ( !path.startsWith( "/" ) ) path = "/" + path; Map<String,Object> _resourceBundleEntries = new HashMap<String,Object>(); URL _path = getClass().getResource( path ); String protocol = _path.getProtocol(); if ("jar".equals(protocol)) { String file = _path.getFile(); //:file:/=5 file = file.substring(5, file.indexOf('!')); JarFile jf = new JarFile(file); Enumeration<JarEntry> jenm = jf.entries(); try { while (jenm.hasMoreElements()) { JarEntry entry = jenm.nextElement(); if (entry.isDirectory()) continue; String jar = entry.getName(); String fileName=null; if(jar.lastIndexOf('/')==-1) fileName=jar; else fileName = jar.substring(jar.lastIndexOf('/')+1,jar.length()); if (SimpleFilter.compareSubstring(SimpleFilter.parseSubstring(filePattern), fileName)) { InputStream is = jf.getInputStream(entry); PropertyResourceBundle prb = new PropertyResourceBundle(null,is); _resourceBundleEntries.put(getEntryPath(fileName), prb); } } } finally{ jf.close(); } }else{ try { File file = new File(_path.toURI()); if (!file.isDirectory()) { String fileName = file.getName(); _resourceBundleEntries.put(getEntryPath(fileName), file.toURI().toURL().openStream()); } else { int k_file_idx=0; File[] files = file.listFiles(); while (files != null && k_file_idx < files.length ) { if (SimpleFilter.compareSubstring(SimpleFilter.parseSubstring(filePattern), files[k_file_idx].getName())) { String fileName = files[k_file_idx].getName(); _resourceBundleEntries.put(getEntryPath(fileName), files[k_file_idx].toURI().toURL().openStream()); } k_file_idx++; } } } catch (URISyntaxException e) { } } return _resourceBundleEntries; } private String getEntryPath(String fileName){ String entryPath=null; if(fileName.indexOf('_')==-1) entryPath="_" + MessageTools.DEFAULT_LOCALE.toString(); else entryPath =fileName.substring(fileName.indexOf('_'),fileName.length()-11); return entryPath; } /** * @param locale * @return */ private Locale getParentLocale(Locale locale) { if (locale.getVariant().length() != 0) { return new Locale(locale.getLanguage(), locale.getCountry()); } else if (locale.getCountry().length() != 0) { return new Locale(locale.getLanguage(), ""); } // no parent return null; } }