/** * (C) Copyright 2013 Jabylon (http://www.jabylon.org) 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 */ package org.jabylon.rest.ui.model; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.ResourceBundle.Control; import java.util.concurrent.ExecutionException; import org.apache.wicket.Component; import org.apache.wicket.Session; import org.apache.wicket.resource.loader.IStringResourceLoader; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; public class OSGiAwareBundleStringResourceLoader implements IStringResourceLoader { private final BundleContext context; private LoadingCache<Integer, ClassLoader> cache; private Logger logger = LoggerFactory.getLogger(OSGiAwareBundleStringResourceLoader.class); /** * to make sure it always reverts to the base bundle instead of the system default locale */ private static final Control CONTROL = ResourceBundle.Control.getNoFallbackControl(Control.FORMAT_PROPERTIES); public OSGiAwareBundleStringResourceLoader() { context = FrameworkUtil.getBundle(getClass()).getBundleContext(); cache = CacheBuilder.newBuilder().build(new CacheLoader<Integer, ClassLoader>() { @Override public ClassLoader load(Integer key) throws Exception { Bundle bundle = context.getBundle(key); String bundleName = bundle.getHeaders().get("Bundle-Localisation"); if(bundleName==null) bundleName = "OSGI-INF/l10n/bundle"; String prefix = "/"+bundleName.substring(0, bundleName.lastIndexOf('/')); Enumeration<URL> entries = bundle.findEntries(prefix, "*.properties", false); List<URL> urls = Collections.emptyList(); if(entries!=null) { urls = new ArrayList<URL>(); while(entries.hasMoreElements()) { URL url = entries.nextElement(); urls.add(url); } } return new BundleClassloader(prefix,urls); } }); } @Override public final String loadStringResource(final Class<?> clazz, final String key, Locale locale, final String style, final String variation) { try { if(key.startsWith("%")) { if (locale == null) { locale = Session.exists() ? Session.get().getLocale() : Locale.getDefault(); } int keyStart = key.indexOf("|"); int bundleId = Integer.parseInt(key.substring(1,keyStart)); Bundle bundle = context.getBundle(bundleId); String bundleName = bundle.getHeaders().get("Bundle-Localisation"); if(bundleName==null) bundleName = "OSGI-INF/l10n/bundle"; return ResourceBundle.getBundle(bundleName, locale,cache.get(bundleId),CONTROL).getString(key.substring(keyStart+1)); } else if(key.startsWith("|")) { //starts with a marker that this key is to be treated as the value return key.substring(1); } return null; } catch (MissingResourceException e) { return null; } catch (ExecutionException e) { logger.warn("Failed to create classloader for key "+key,e); return null; } } @Override public final String loadStringResource(final Component component, final String key, Locale locale, final String style, final String variation) { return loadStringResource((Class<?>)null, key, locale, style, variation); } } class BundleClassloader extends ClassLoader { private Map<String, URL> resources; private int prefixLength; public BundleClassloader(String prefix, List<URL> urls) { resources = new HashMap<String, URL>(); prefixLength = prefix.length(); for (URL url : urls) { String path = url.getPath(); resources.put(path.substring(path.lastIndexOf('/')+1),url); } } @Override protected URL findResource(String name) { if(name.length()<prefixLength) return null; return resources.get(name.substring(prefixLength)); } }