/* * 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.apache.felix.metatype.internal.l10n; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.StringTokenizer; import org.osgi.framework.Bundle; import org.osgi.service.metatype.MetaTypeService; /** * The <code>BundleResources</code> TODO * * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> */ public class BundleResources { private Bundle bundle; private long bundleLastModified; private Map resourcesByLocale; private static Map resourcesByBundle = null; public static Resources getResources( Bundle bundle, String basename, String locale ) { BundleResources bundleResources = null; if ( resourcesByBundle != null ) { // the bundle has been uninstalled, ensure removed from the cache // and return null (e.g. no resources now) if ( bundle.getState() == Bundle.UNINSTALLED ) { resourcesByBundle.remove( new Long( bundle.getBundleId() ) ); return null; } // else check whether we know the bundle already bundleResources = ( BundleResources ) resourcesByBundle.get( new Long( bundle.getBundleId() ) ); } else { // create the cache to be used for a newly created BundleResources resourcesByBundle = new HashMap(); } if ( bundleResources == null ) { bundleResources = new BundleResources( bundle ); resourcesByBundle.put( new Long( bundle.getBundleId() ), bundleResources ); } return bundleResources.getResources( basename, locale ); } public static void clearResourcesCache() { resourcesByBundle = null; } private BundleResources( Bundle bundle ) { this.bundle = bundle; this.bundleLastModified = bundle.getLastModified(); this.resourcesByLocale = new HashMap(); } private boolean isUpToDate() { return bundle.getState() != Bundle.UNINSTALLED && bundleLastModified >= bundle.getLastModified(); } private Resources getResources( String basename, String locale ) { // ensure locale - use VM default locale if null if ( locale == null ) { locale = Locale.getDefault().toString(); } final String key = basename + "-" + locale; // check the cache, if the bundle has not changed if ( isUpToDate() ) { Resources res = ( Resources ) resourcesByLocale.get( key ); if ( res != null ) { return res; } } else { // otherwise clear the cache resourcesByLocale.clear(); } // get the list of potential resource names files Properties parentProperties = null; List resList = createResourceList( locale ); for ( Iterator ri = resList.iterator(); ri.hasNext(); ) { final String tmpLocale = ( String ) ri.next(); final String tmpKey = basename + "-" + tmpLocale; Resources res = ( Resources ) resourcesByLocale.get( tmpKey ); if ( res != null ) { parentProperties = res.getResources(); } else { Properties props = loadProperties( basename, tmpLocale, parentProperties ); res = new Resources( tmpLocale, props ); resourcesByLocale.put( tmpKey, res ); parentProperties = props; } } // just return from the cache again return ( Resources ) resourcesByLocale.get( key ); } private Properties loadProperties( String basename, String locale, Properties parentProperties ) { String resourceName = basename; if ( locale != null && locale.length() > 0 ) { resourceName += "_" + locale; } resourceName += ".properties"; Properties props = new Properties( parentProperties ); // FELIX-5173 - allow the resource to be provided by fragments as well... URL resURL = bundle.getResource( resourceName ); // FELIX-607 backwards compatibility, support if ( resURL == null ) { // FELIX-5173 - allow the resource to be provided by fragments as well... resURL = bundle.getResource( MetaTypeService.METATYPE_DOCUMENTS_LOCATION + "/" + resourceName ); } if ( resURL != null ) { InputStream ins = null; try { ins = resURL.openStream(); props.load( ins ); } catch ( IOException ex ) { // File doesn't exist, just continue loop } finally { if ( ins != null ) { try { ins.close(); } catch ( IOException ignore ) { } } } } return props; } private List createResourceList( String locale ) { List result = new ArrayList( 4 ); StringTokenizer tokens; StringBuffer tempLocale = new StringBuffer(); result.add( tempLocale.toString() ); if ( locale != null && locale.length() > 0 ) { tokens = new StringTokenizer( locale, "_" ); while ( tokens.hasMoreTokens() ) { if ( tempLocale.length() > 0 ) { tempLocale.append( "_" ); } tempLocale.append( tokens.nextToken() ); result.add( tempLocale.toString() ); } } return result; } }