/**
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
* the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
*
* Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
* graphic logo is a trademark of OpenMRS Inc.
*/
package org.openmrs.web.filter.util;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.openmrs.util.DatabaseUpdater;
import org.openmrs.util.DatabaseUtil;
import org.openmrs.util.OpenmrsConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class contains convenient methods for storing/retrieving locale parameters into/from DB as
* admin's user property and as default locale property for OpenMRS system
*/
public class FilterUtil {
private static final Logger log = LoggerFactory.getLogger(FilterUtil.class);
public static final String LOCALE_ATTRIBUTE = "locale";
public static final String REMEMBER_ATTRIBUTE = "remember";
public static final String ADMIN_USERNAME = "admin";
/**
* Tries to retrieve location parameter. First this method makes an attempt to load locale
* parameter as user's property. And next, if user's property is empty it tries to retrieve
* default system locale (i.e system global property). If it also is empty it uses default value
* for system locale
*
* @param username the name of the administrative user whose default locale property will be
* restored
* @return string with stored location parameter or default OpenMRS locale property's value
*/
public static String restoreLocale(String username) {
String currentLocale = null;
if (StringUtils.isNotBlank(username)) {
PreparedStatement statement = null;
Connection connection = null;
try {
connection = DatabaseUpdater.getConnection();
// first we should try to get locale parameter as user's property
Integer userId = getUserIdByName(username, connection);
if (userId != null) {
String select = "select property_value from user_property where user_id = ? and property = ?";
statement = connection.prepareStatement(select);
statement.setInt(1, userId);
statement.setString(2, OpenmrsConstants.USER_PROPERTY_DEFAULT_LOCALE);
if (statement.execute()) {
ResultSet results = statement.getResultSet();
if (results.next()) {
currentLocale = results.getString(1);
}
}
//close statement
statement.close();
}
// if locale is still null we should try to retrieve system locale global property's value
if (currentLocale == null) {
currentLocale = readSystemDefaultLocale(connection);
}
}
catch (Exception e) {
log.error("Error while retriving locale property", e);
}
finally {
try {
if (statement != null && !statement.isClosed()) {
statement.close();
}
}
catch (SQLException e) {
log.warn("Error while closing statement");
}
if (connection != null) {
try {
connection.close();
}
catch (SQLException e) {
log.debug("Error while closing the database", e);
}
}
}
}
// if locale is still null we just simply using default locale value (i.e. en_GB)
if (currentLocale == null) {
currentLocale = OpenmrsConstants.GLOBAL_PROPERTY_DEFAULT_LOCALE_DEFAULT_VALUE;
}
return currentLocale;
}
/**
* This method uses passed in connection to load system default locale. If connection is passed
* as null it creates separate connection that should be closed before return from method
*
* @param connection (optional) the jdbc connection to be used for extracting default locale
* @return the string that contains system default locale or null
*/
public static String readSystemDefaultLocale(Connection connection) {
String systemDefaultLocale = null;
Boolean needToCloseConection = false;
try {
if (connection == null) {
connection = DatabaseUpdater.getConnection();
needToCloseConection = true;
}
String select = "select property_value from global_property where property = ?";
PreparedStatement statement = connection.prepareStatement(select);
statement.setString(1, OpenmrsConstants.GLOBAL_PROPERTY_DEFAULT_LOCALE);
if (statement.execute()) {
ResultSet results = statement.getResultSet();
if (results.next()) {
systemDefaultLocale = results.getString(1);
}
}
}
catch (Exception e) {
log.error("Error while retrieving system default locale", e);
}
finally {
if (needToCloseConection && connection != null) {
try {
connection.close();
}
catch (SQLException e) {
log.debug("Error while closing the database", e);
}
}
}
return systemDefaultLocale;
}
/**
* Stores selected by user locale into DB as admin's user property and as system default locale
*
* @param locale the selected by user language
* @return true if locale was stored successfully
*/
public static boolean storeLocale(String locale) {
if (StringUtils.isNotBlank(locale)) {
Connection connection = null;
Integer userId = null;
try {
connection = DatabaseUpdater.getConnection();
// first we should try to get admin user id
userId = getUserIdByName(ADMIN_USERNAME, connection);
// first we are saving locale as administrative user's property
if (userId != null) {
String insert = "insert into user_property (user_id, property, property_value) values (?, 'defaultLocale', ?)";
PreparedStatement statement = null;
try {
statement = connection.prepareStatement(insert);
statement.setInt(1, userId);
statement.setString(2, locale);
if (statement.executeUpdate() != 1) {
log.warn("Unable to save user locale as admin property.");
}
}
finally {
if (statement != null) {
try {
statement.close();
}
catch (Exception statementCloseEx) {
log.error("Failed to quietly close Statement", statementCloseEx);
}
}
}
}
// and the second step is to save locale as system default locale global property
String update = "update global_property set property_value = ? where property = ? ";
PreparedStatement statement = null;
try {
statement = connection.prepareStatement(update);
statement.setString(1, locale);
statement.setString(2, OpenmrsConstants.GLOBAL_PROPERTY_DEFAULT_LOCALE);
if (statement.executeUpdate() != 1) {
log.warn("Unable to set system default locale property.");
}
}
finally {
if (statement != null) {
try {
statement.close();
}
catch (Exception statementCloseEx) {
log.error("Failed to quietly close Statement", statementCloseEx);
}
}
}
}
catch (Exception e) {
log.warn("Locale " + locale + " could not be set for user with id " + userId + " .", e);
return false;
}
finally {
if (connection != null) {
try {
connection.close();
}
catch (SQLException e) {
log.debug("Error while closing the database", e);
}
}
}
return true;
}
return false;
}
/**
* This is a utility method that can be used for retrieving user id by given user name and sql
* connection
*
* @param userNameOrSystemId the name of user
* @param connection the java sql connection to use
* @return not null id of given user in case of success or null otherwise
* @throws SQLException
*/
public static Integer getUserIdByName(String userNameOrSystemId, Connection connection) throws SQLException {
String select = "select user_id from users where system_id = ? or username = ?";
PreparedStatement statement = connection.prepareStatement(select);
statement.setString(1, userNameOrSystemId);
statement.setString(2, userNameOrSystemId);
Integer userId = null;
if (statement.execute()) {
ResultSet results = statement.getResultSet();
if (results.next()) {
userId = results.getInt(1);
}
}
return userId;
}
/**
* Gets the value of a global Property as a string from the database using sql, this method is
* useful when you want to get a value of a global property before the application context has
* been setup
*
* @param globalPropertyName the name of the global property
* @return the global property value
*/
public static String getGlobalPropertyValue(String globalPropertyName) {
String propertyValue = null;
Connection connection = null;
try {
connection = DatabaseUpdater.getConnection();
List<List<Object>> results = DatabaseUtil.executeSQL(connection,
"select property_value from global_property where property = '" + globalPropertyName + "'", true);
if (results.size() == 1 && results.get(0).size() == 1) {
propertyValue = results.get(0).get(0).toString();
}
}
catch (Exception e) {
log.error("Error while retrieving value for global property:" + globalPropertyName, e);
}
finally {
if (connection != null) {
try {
connection.close();
}
catch (SQLException e) {
log.debug("Error while closing the database connection", e);
}
}
}
return propertyValue;
}
}