/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program 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.
*
* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.platform.web.servlet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONException;
import org.json.JSONObject;
import org.pentaho.platform.api.engine.IPluginManager;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.util.messages.LocaleHelper;
import org.pentaho.platform.web.servlet.messages.Messages;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ResourceBundle;
/**
* This class makes a message bundle available as a JSON hash. This is designed to be used as a web service to allow
* thin-clients to retrieve message bundles from the server.
*
* @author Jordan Ganoff (jganoff@pentaho.com)
*/
public class LocalizationServlet extends ServletBase {
private static final Log logger = LogFactory.getLog( LocalizationServlet.class );
private static final String DEFAULT_CACHE_MESSAGES_SETTING = "false"; //$NON-NLS-1$
@Override
public Log getLogger() {
return logger;
}
@Override
public void doGet( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException {
doPost( req, resp );
}
@Override
public void doPost( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException {
String pluginId = req.getParameter( "plugin" ); //$NON-NLS-1$
String name = req.getParameter( "name" ); //$NON-NLS-1$
try {
String json = getJSONBundle( pluginId, name );
resp.setContentType( "text/plain" ); //$NON-NLS-1$
resp.setStatus( HttpServletResponse.SC_OK );
resp.setCharacterEncoding( LocaleHelper.getSystemEncoding() );
PrintWriter writer = resp.getWriter();
try {
writer.write( json );
} finally {
writer.close();
}
} catch ( Exception ex ) {
error( Messages.getInstance().getErrorString( "LocalizationServlet.ERROR_0000_ERROR" ), ex ); //$NON-NLS-1$
resp.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
}
}
/**
* Retrieve a {@link java.util.ResourceBundle} from a plugin.
*
* @param pluginId
* ID of the plugin to load the resource bundle from
* @param name
* Resource bundle name that resides in the plugin
* @return Resource bundle for the name provided in the plugin referenced by {@code pluginId}
* @throws IllegalArgumentException
* Invalid plugin Id
* @throws java.util.MissingResourceException
* Invalid resource bundle name
*/
protected ResourceBundle getBundle( String pluginId, String name ) {
IPluginManager pm = PentahoSystem.get( IPluginManager.class );
ClassLoader pluginClassLoader = pm.getClassLoader( pluginId );
if ( pluginClassLoader == null ) {
throw new IllegalArgumentException( Messages.getInstance().getErrorString(
"LocalizationServlet.ERROR_0001_INVALID_PLUGIN_ID", pluginId ) ); //$NON-NLS-1$
}
if ( name == null || name.length() == 0 ) {
throw new IllegalArgumentException( Messages.getInstance().getErrorString(
"LocalizationServlet.ERROR_0002_INVALID_RESOURCE_NAME", name ) ); //$NON-NLS-1$
}
ResourceBundle bundle = ResourceBundle.getBundle( name, LocaleHelper.getLocale(), pluginClassLoader );
// Clear the bundle's cached messages if we shouldn't be caching them
if ( !isMessageCachingEnabled( pm, pluginId ) ) {
ResourceBundle.clearCache();
}
return bundle;
}
/**
* Should the messages in the Resource Bundle be cached?
*
* @param pm
* Plugin manager
* @param pluginId
* ID of plugin whose "cache-messages" setting should be checked
* @return {@code true} if the localization messages loaded from this plugin should be cached
*/
public boolean isMessageCachingEnabled( IPluginManager pm, String pluginId ) {
Object cache = pm.getPluginSetting( pluginId, "cache-messages", DEFAULT_CACHE_MESSAGES_SETTING ); //$NON-NLS-1$
// Check whether we want to clear the bundle cache which is useful to test resource file changes
return !DEFAULT_CACHE_MESSAGES_SETTING.equals( cache );
}
/**
* Load the resource bundle for the plugin provided and return the resulting properties map as JSON. This is intended
* to be used with Dojo's i18n system
* (http://dojotoolkit.org/reference-guide/1.7/quickstart/internationalization/index
* .html#quickstart-internationalization-index)
*
* @param pluginId
* ID of plugin to load the resource from
* @param name
* Name of the resource to load
* @return JSON String with a hash of key/value pairs representing properties from the requested resource bundle
*/
public String getJSONBundle( String pluginId, String name ) {
try {
return getJsonForBundle( getBundle( pluginId, name ) );
} catch ( Exception e ) {
throw new RuntimeException( e.toString(), e );
}
}
/**
* Convert a {@see ResourceBundle} into a JSON string.
*
* @param bundle
* Resource bundle to convert
* @return Bundle with all key/value pairs as entries in a hash, returned as a JSON string.
* @throws org.json.JSONException
*/
protected String getJsonForBundle( ResourceBundle bundle ) throws JSONException {
JSONObject cat = new JSONObject();
for ( String key : bundle.keySet() ) {
cat.put( key, bundle.getString( key ) );
}
return cat.toString();
}
}