/*
* ConcourseConnect
* Copyright 2009 Concursive Corporation
* http://www.concursive.com
*
* This file is part of ConcourseConnect, an open source social business
* software and community platform.
*
* Concursive ConcourseConnect is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, version 3 of the License.
*
* Under the terms of the GNU Affero General Public License you must release the
* complete source code for any application that uses any part of ConcourseConnect
* (system header files and libraries used by the operating system are excluded).
* These terms must be included in any work that has ConcourseConnect components.
* If you are developing and distributing open source applications under the
* GNU Affero General Public License, then you are free to use ConcourseConnect
* under the GNU Affero General Public License.
*
* If you are deploying a web site in which users interact with any portion of
* ConcourseConnect over a network, the complete source code changes must be made
* available. For example, include a link to the source archive directly from
* your web site.
*
* For OEMs, ISVs, SIs and VARs who distribute ConcourseConnect with their
* products, and do not license and distribute their source code under the GNU
* Affero General Public License, Concursive provides a flexible commercial
* license.
*
* To anyone in doubt, we recommend the commercial license. Our commercial license
* is competitively priced and will eliminate any confusion about how
* ConcourseConnect can be used and distributed.
*
* ConcourseConnect 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 Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with ConcourseConnect. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution Notice: ConcourseConnect is an Original Work of software created
* by Concursive Corporation
*/
package com.concursive.connect.config;
import com.concursive.commons.codec.PrivateString;
import com.concursive.commons.db.ConnectionElement;
import com.concursive.commons.db.ConnectionPool;
import com.concursive.commons.jsp.JspUtils;
import com.concursive.commons.workflow.ObjectHookManager;
import com.concursive.commons.xml.XMLUtils;
import com.concursive.connect.Constants;
import com.concursive.connect.cache.CacheContext;
import com.concursive.connect.cache.Caches;
import com.concursive.connect.indexer.IndexerContext;
import com.concursive.connect.indexer.IndexerFactory;
import com.concursive.connect.scheduler.ScheduledJobs;
import com.concursive.connect.web.modules.upgrade.utils.UpgradeUtils;
import com.concursive.connect.web.webdav.WebdavManager;
import com.concursive.connect.workflow.utils.WorkflowUtils;
import freemarker.cache.FileTemplateLoader;
import freemarker.cache.MultiTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.cache.WebappTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Scheduler;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import javax.servlet.ServletContext;
import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.security.Key;
import java.sql.Connection;
import java.text.NumberFormat;
import java.util.*;
import java.util.prefs.Preferences;
/**
* Handles storing and retrieving web application preferences
*
* @author matt rajkowski
* @version $Id: ApplicationPrefs.java,v 2.18.2.1 2004/09/13 02:30:47 matt Exp
* $
* @created August 26, 2003
*/
public class ApplicationPrefs {
private static Log LOG = LogFactory.getLog(ApplicationPrefs.class);
public final static String GENERATED_MESSAGE = "### GENERATED BY com.concursive.connect.config.ApplicationPrefs";
// Object constants
public final static String FILE_LIBRARY_PATH = "FILELIBRARY";
public final static String TEAM_KEY = "TEAM.KEY";
// Connection Properties
public final static String CONNECTION_DRIVER = "SITE.DRIVER";
public final static String CONNECTION_URL = "SITE.URL";
public final static String CONNECTION_USER = "SITE.USER";
public final static String CONNECTION_PASSWORD = "SITE.PASSWORD";
// Connection Pool Properties
public final static String CONNECTION_POOL_DEBUG = "CONNECTION_POOL.DEBUG";
public final static String CONNECTION_POOL_TEST_CONNECTIONS = "CONNECTION_POOL.TEST_CONNECTIONS";
public final static String CONNECTION_POOL_ALLOW_SHRINKING = "CONNECTION_POOL.ALLOW_SHRINKING";
public final static String CONNECTION_POOL_MAX_CONNECTIONS = "CONNECTION_POOL.MAX_CONNECTIONS";
public final static String CONNECTION_POOL_MAX_IDLE_TIME = "CONNECTION_POOL.MAX_IDLE_TIME.SECONDS";
public final static String CONNECTION_POOL_MAX_DEAD_TIME = "CONNECTION_POOL.MAX_DEAD_TIME.SECONDS";
public final static String CONNECTION_POOL_MAX_RSS_CONNECTIONS = "CONNECTION_POOL.MAX_CONNECTIONS.RSS";
public final static String CONNECTION_POOL_MAX_API_CONNECTIONS = "CONNECTION_POOL.MAX_CONNECTIONS.API";
public final static String CONNECTION_POOL_MAX_WORKFLOW_CONNECTIONS = "CONNECTION_POOL.MAX_CONNECTIONS.WORKFLOW";
public final static String CONNECTION_POOL_MAX_SCHEDULER_CONNECTIONS = "CONNECTION_POOL.MAX_CONNECTIONS.APPS";
public final static String CONNECTION_POOL_MAX_CACHE_CONNECTIONS = "CONNECTION_POOL.MAX_CONNECTIONS.CACHE";
// Mail Server Properties
public final static String MAILSERVER = "MAILSERVER";
public final static String MAILSERVER_USERNAME = "MAILSERVER.CONNECTION.USERNAME";
public final static String MAILSERVER_PASSWORD = "MAILSERVER.CONNECTION.PASSWORD";
public final static String MAILSERVER_PORT = "MAILSERVER.CONNECTION.PORT";
public final static String MAILSERVER_SSL = "MAILSERVER.CONNECTION.SSL";
public final static String EMAILADDRESS = "EMAILADDRESS";
// DimDim Properties
public final static String DIMDIM_ENABLED = "DIMDIM.ENABLED";
public final static String DIMDIM_API_DOMAIN = "DIMDIM.DOMAIN";
// Google Properties
public final static String GOOGLE_MAPS_API_DOMAIN = "GOOGLE_MAPS.DOMAIN";
public final static String GOOGLE_MAPS_API_KEY = "GOOGLE_MAPS.KEY";
public final static String GOOGLE_ANALYTICS_ID = "GOOGLE_ANALYTICS.ID";
public final static String GOOGLE_ANALYTICS_VERIFY = "GOOGLE_ANALYTICS.VERIFY";
// Twitter Properties
public final static String TWITTER_HASH = "TWITTER_HASH";
// Services Properties
public final static String CONCURSIVE_SERVICES_SERVER = "CONCURSIVE_SERVICES.SERVER";
public final static String CONCURSIVE_SERVICES_ID = "CONCURSIVE_SERVICES.ID";
public final static String CONCURSIVE_SERVICES_KEY = "CONCURSIVE_SERVICES.KEY";
public final static String CONSUMER_SESSION_SUPPORT = "CONSUMER_SESSION_SUPPORT";
// Web Application Behavior Properties
public final static String LOGIN_MODE = "LOGIN.MODE";
public final static String PURPOSE = "PURPOSE";
// The Application's URL
public final static String WEB_SCHEME = "URL.SCHEME";
public final static String WEB_DOMAIN_NAME = "URL.DOMAIN_NAME";
public final static String WEB_PORT = "URL.PORT";
public final static String WEB_CONTEXT = "URL.CONTEXT";
// Web Application Look and Feel
public final static String THEME = "THEME";
public final static String COLOR_SCHEME = "COLOR_SCHEME";
public final static String JSP_TEMPLATE = "TEMPLATE";
public final static String CSS_FILE = "CSS";
public final static String HOME_URL = "PORTAL.INDEX";
public final static String WEB_PAGE_TITLE = "TITLE";
public final static String WEB_PAGE_DESCRIPTION = "DESCRIPTION";
public final static String WEB_PAGE_KEYWORDS = "KEYWORDS";
public final static String WEB_PAGE_LOGO = "LOGO";
// Application Behavior Properties
public final static String WORKFLOW_FILE = "WORKFLOW";
public final static String SYSTEM_SETTINGS_FILE = "SETTINGS";
public final static String USERS_CAN_REGISTER = "REGISTER";
public final static String INFORMATION_IS_SENSITIVE = "SENSITIVE_INFORMATION";
public final static String USERS_CAN_INVITE = "INVITE";
public final static String USERS_CAN_START_PROJECTS = "START_PROJECTS";
public final static String USERS_ARE_ANONYMOUS = "ANONYMOUS";
public final static String DEFAULT_USER_PROFILE_ROLE = "DEFAULT_USER_PROFILE_ROLE";
public final static String DEFAULT_USER_PROFILE_TABS = "DEFAULT_USER_PROFILE_TABS";
public final static String SHOW_TERMS_AND_CONDITIONS = "LICENSE";
public final static String SEARCH_USES_LOCATION = "USE_LOCATIONS";
public final static String LANGUAGE = "SYSTEM.LANGUAGE";
public final static String TIMEZONE = "SYSTEM.TIMEZONE";
public final static String CURRENCY = "SYSTEM.CURRENCY";
public final static String LANGUAGES_SUPPORTED = "SUPPORTED.LANGUAGES";
public final static String MAIN_PROFILE = "MAIN_PROFILE";
public final static String SHOW_HOLIDAYS = "HOLIDAYS";
// Default values
public final static String DEFAULT_NODE = "primary";
// Community Management Settings
public final static String CONCURSIVE_CRM_SERVER = "CONCURSIVE_CRM.SERVER";
public final static String CONCURSIVE_CRM_ID = "CONCURSIVE_CRM.ID";
public final static String CONCURSIVE_CRM_CODE = "CONCURSIVE_CRM.CODE";
public final static String CONCURSIVE_CRM_CLIENT = "CONCURSIVE_CRM.CLIENT";
// System constants
public final static String ls = System.getProperty("line.separator");
public final static String fs = System.getProperty("file.separator");
// Variable context properties
private String node = null;
private Map<String, Dictionary> dictionaries = new HashMap<String, Dictionary>();
private Map<String, String> prefs = new LinkedHashMap<String, String>();
private Map<String, String> nodePrefs = new LinkedHashMap<String, String>();
/**
* Constructor for the ApplicationPrefs object
*/
public ApplicationPrefs() {
}
/**
* Constructor for the ApplicationPrefs object
*
* @param context Description of the Parameter
*/
public ApplicationPrefs(ServletContext context) {
initializePrefs(context);
}
/**
* Description of the Method
*
* @param param Description of the Parameter
* @return Description of the Return Value
*/
public String get(String param) {
String value = nodePrefs.get(param);
if (value == null) {
value = prefs.get(param);
}
return value;
}
public String get(String param, String defaultValue) {
String value = get(param);
if (value == null) {
return defaultValue;
}
return value;
}
/**
* Description of the Method
*
* @param param Description of the Parameter
* @return Description of the Return Value
*/
public boolean has(String param) {
return (prefs.containsKey(param) || nodePrefs.containsKey(param));
}
/**
* Description of the Method
*
* @param param Description of the Parameter
* @param value Description of the Parameter
*/
public void add(String param, String value) {
if (param != null) {
if (value != null) {
prefs.put(param, value);
} else {
prefs.remove(param);
}
}
}
public void add(String param, boolean value) {
add(param, (value ? "true" : "false"));
}
public Map<String, String> getPrefs() {
Map<String, String> allPrefs = new LinkedHashMap<String, String>();
allPrefs.putAll(prefs);
allPrefs.putAll(nodePrefs);
return allPrefs;
}
/**
* Description of the Method
*/
public void clear() {
prefs.clear();
nodePrefs.clear();
}
/**
* Initializes preferences
*
* @param context ServletContext
*/
public void initializePrefs(ServletContext context) {
LOG.info("Initializing...");
// Load the application node name, if any
try {
Properties instanceProperties = new Properties();
instanceProperties.load(context.getResourceAsStream("/WEB-INF/instance.property"));
node = instanceProperties.getProperty("node", DEFAULT_NODE);
LOG.info("Node: " + node);
} catch (Exception e) {
LOG.info("Default Node: " + DEFAULT_NODE);
node = DEFAULT_NODE;
}
// Determine the file library
String fileLibrary = retrieveFileLibraryLocation(context);
if (fileLibrary != null) {
loadProperties(fileLibrary);
this.add(FILE_LIBRARY_PATH, fileLibrary);
configureDebug();
verifyKey(context, fileLibrary);
configureConnectionPool(context);
configureFreemarker(context);
configureWebdavManager(context);
configureSystemSettings(context);
configureCache(context);
if (isConfigured()) {
if (ApplicationVersion.isOutOfDate(this)) {
LOG.info("Upgrade triggered... obtaining lock to continue");
// Use a lock file to to start upgrading
File upgradeLockFile = new File(fileLibrary + "upgrade.lock");
FileChannel fileChannel = null;
FileLock fileLock = null;
try {
// Configure the file for locking
fileChannel = new RandomAccessFile(upgradeLockFile, "rw").getChannel();
// Use fileChannel.lock which blocks until the lock is obtained
fileLock = fileChannel.lock();
// Reload the prefs to make sure the upgrade isn't already complete
loadProperties(fileLibrary);
if (ApplicationVersion.isOutOfDate(this)) {
// The application needs an update
LOG.info("Installed version " + ApplicationVersion.getInstalledVersion(this) + " will be upgraded to " + ApplicationVersion.VERSION);
performUpgrade(context);
}
} catch (Exception e) {
LOG.error("initializePrefs-> performUpgrade", e);
} finally {
try {
if (fileLock != null) {
fileLock.release();
}
if (fileChannel != null) {
fileChannel.close();
}
} catch (Exception eclose) {
LOG.error("initializePrefs-> lock", eclose);
}
}
}
if (!ApplicationVersion.isOutOfDate(this)) {
// Start the services now that everything is ready
initializeServices(context);
}
}
}
configureDefaultBehavior(context);
loadApplicationDictionaries(context);
}
/**
* Initializes services
*
* @param context ServletContext
*/
public void initializeServices(ServletContext context) {
// These require up-to-date objects, so postpone if an update is needed
configureWorkflowManager(context);
configureScheduler(context);
configureIndexer();
}
/**
* Description of the Method
*
* @param context Description of the Parameter
* @return Description of the Return Value
*/
private String retrieveFileLibraryLocation(ServletContext context) {
String dir = ApplicationPrefs.getRealPath(context);
try {
if (dir == null) {
dir = node;
}
// Read from Preferences
LOG.info("Java preferences key: " + dir);
Preferences javaPrefs = Preferences.userNodeForPackage(ApplicationPrefs.class);
// Check "dir" prefs first, based on the installed directory of this webapp
String fileLibrary = null;
if (dir.length() <= Preferences.MAX_KEY_LENGTH) {
fileLibrary = javaPrefs.get(dir, null);
} else {
fileLibrary = javaPrefs.get(dir.substring(dir.length() - Preferences.MAX_KEY_LENGTH), null);
}
boolean doSave = false;
// Preferences not found
if (fileLibrary == null) {
// Check in the current dir of the webapp for a pointer to the properties
// NOTE: Some containers return null for getRealPath()
String realPath = ApplicationPrefs.getRealPath(context);
if (realPath != null) {
fileLibrary = realPath + "WEB-INF" + fs + "fileLibrary" + fs;
doSave = true;
}
}
// See if properties exist
if (fileLibrary != null) {
File propertyFile = new File(fileLibrary + "build.properties");
if (propertyFile.exists()) {
if (doSave) {
saveFileLibraryLocation(dir, fileLibrary);
}
return fileLibrary;
}
}
} catch (Exception e) {
LOG.error("ApplicationPrefs", e);
e.printStackTrace(System.out);
}
return null;
}
/**
* Constructor for the ApplicationPrefs object
*
* @param path Description of the Parameter
*/
public void loadProperties(String path) {
this.clear();
// Application properties
loadProperties(path, "build.properties", prefs);
// Any node properties
File nodeFile = new File(path + "instances" + fs + node + ".properties");
if (nodeFile.exists()) {
loadProperties(path + "instances" + fs, node + ".properties", nodePrefs);
}
}
private void loadProperties(String path, String filename, Map<String, String> prefsToAddTo) {
try {
BufferedReader in = new BufferedReader(new FileReader(path + filename));
String line = null;
int count = 0;
while ((line = in.readLine()) != null) {
++count;
if (!line.startsWith("#") && line.indexOf("=") > 0) {
String param = line.substring(0, line.indexOf("="));
String value = "";
if (line.indexOf("=") + 1 < line.length()) {
value = line.substring(line.indexOf("=") + 1);
}
prefsToAddTo.put(param, value);
} else if (!line.startsWith(GENERATED_MESSAGE)) {
prefsToAddTo.put("#" + count, line);
}
}
in.close();
LOG.info("Read properties: " + path + filename + " (" + count + ")");
} catch (Exception e) {
LOG.error("Could not load properties from: " + path + filename, e);
}
}
/**
* Description of the Method
*/
private void configureDebug() {
if (this.has("DEBUG")) {
System.setProperty("Debug", this.get("DEBUG"));
System.setProperty("DEBUG", this.get("DEBUG"));
}
}
/**
* Description of the Method
*
* @param context Description of the Parameter
* @param fileLibrary Description of the Parameter
*/
private void verifyKey(ServletContext context, String fileLibrary) {
// Configure the encryption key
Key key = PrivateString.generateKeyFile(fileLibrary + "team.key");
context.setAttribute(TEAM_KEY, key);
}
/**
* Description of the Method
*
* @param context Description of the Parameter
*/
public void configureConnectionPool(ServletContext context) {
LOG.info("configureConnectionPool");
//Define the ConnectionPool, else defaults from the ContextListener will be used
ConnectionPool cp = (ConnectionPool) context.getAttribute(Constants.CONNECTION_POOL);
if (cp != null) {
// Apply any settings
if (this.has(CONNECTION_POOL_DEBUG)) {
cp.setDebug(this.get(CONNECTION_POOL_DEBUG));
}
if (this.has(CONNECTION_POOL_TEST_CONNECTIONS)) {
cp.setTestConnections(this.get(CONNECTION_POOL_TEST_CONNECTIONS));
}
if (this.has(CONNECTION_POOL_ALLOW_SHRINKING)) {
cp.setAllowShrinking(this.get(CONNECTION_POOL_ALLOW_SHRINKING));
}
if (this.has(CONNECTION_POOL_MAX_CONNECTIONS)) {
cp.setMaxConnections(this.get(CONNECTION_POOL_MAX_CONNECTIONS));
}
if (this.has(CONNECTION_POOL_MAX_IDLE_TIME)) {
cp.setMaxIdleTimeSeconds(this.get(CONNECTION_POOL_MAX_IDLE_TIME));
}
if (this.has(CONNECTION_POOL_MAX_DEAD_TIME)) {
cp.setMaxDeadTimeSeconds(this.get(CONNECTION_POOL_MAX_DEAD_TIME));
}
// Clone it for RSS Feeds
if (this.get(CONNECTION_POOL_MAX_RSS_CONNECTIONS) != null) {
ConnectionPool rssCP = new ConnectionPool();
rssCP.setDebug(cp.getDebug());
rssCP.setTestConnections(cp.getTestConnections());
rssCP.setAllowShrinking(cp.getAllowShrinking());
rssCP.setMaxConnections(this.get(CONNECTION_POOL_MAX_RSS_CONNECTIONS));
rssCP.setMaxIdleTime(cp.getMaxIdleTime());
rssCP.setMaxDeadTime(cp.getMaxDeadTime());
context.setAttribute(Constants.CONNECTION_POOL_RSS, rssCP);
} else {
context.setAttribute(Constants.CONNECTION_POOL_RSS, cp);
}
// Clone it for API Requests
if (this.get(CONNECTION_POOL_MAX_API_CONNECTIONS) != null) {
ConnectionPool apiCP = new ConnectionPool();
apiCP.setDebug(cp.getDebug());
apiCP.setTestConnections(cp.getTestConnections());
apiCP.setAllowShrinking(cp.getAllowShrinking());
apiCP.setMaxConnections(this.get(CONNECTION_POOL_MAX_API_CONNECTIONS));
apiCP.setMaxIdleTime(cp.getMaxIdleTime());
apiCP.setMaxDeadTime(cp.getMaxDeadTime());
context.setAttribute(Constants.CONNECTION_POOL_API, apiCP);
} else {
context.setAttribute(Constants.CONNECTION_POOL_API, cp);
}
} else {
LOG.error("ConnectionPool is null");
}
}
/**
* Description of the Method
*
* @param context Description of the Parameter
*/
public void configureWorkflowManager(ServletContext context) {
// Load the defaults
ObjectHookManager hookManager = (ObjectHookManager) context.getAttribute(Constants.OBJECT_HOOK_MANAGER);
if (hookManager != null) {
// Configure a few settings
hookManager.setFileLibraryPath(this.get(FILE_LIBRARY_PATH));
hookManager.setApplicationPrefs(this.getPrefs());
if (ApplicationPrefs.getFreemarkerConfiguration(context) == null) {
LOG.error("Free marker configuration is null");
}
hookManager.setFreemarkerConfiguration(ApplicationPrefs.getFreemarkerConfiguration(context));
hookManager.setKey((Key) context.getAttribute(TEAM_KEY));
Scheduler scheduler = (Scheduler) context.getAttribute(Constants.SCHEDULER);
hookManager.setScheduler(scheduler);
try {
// Configure a separate connection pool
ConnectionPool commonCP = (ConnectionPool) context.getAttribute(Constants.CONNECTION_POOL);
if (commonCP != null) {
if (!this.has(CONNECTION_POOL_MAX_WORKFLOW_CONNECTIONS)) {
hookManager.setConnectionPool((ConnectionPool) context.getAttribute(Constants.CONNECTION_POOL));
} else {
ConnectionPool workflowCP = new ConnectionPool();
workflowCP.setDebug(commonCP.getDebug());
workflowCP.setTestConnections(commonCP.getTestConnections());
workflowCP.setAllowShrinking(commonCP.getAllowShrinking());
workflowCP.setMaxConnections(this.get(CONNECTION_POOL_MAX_WORKFLOW_CONNECTIONS));
workflowCP.setMaxIdleTime(commonCP.getMaxIdleTime());
workflowCP.setMaxDeadTime(commonCP.getMaxDeadTime());
hookManager.setConnectionPool(workflowCP);
}
}
ConnectionElement ce = new ConnectionElement();
ce.setDriver(this.get(CONNECTION_DRIVER));
ce.setUrl(this.get(CONNECTION_URL));
ce.setUsername(this.get(CONNECTION_USER));
ce.setPassword(this.get(CONNECTION_PASSWORD));
hookManager.setConnectionElement(ce);
WorkflowUtils.addWorkflow(hookManager, context);
} catch (Exception e) {
e.printStackTrace(System.out);
LOG.error("Workflow Error: " + e.getMessage(), e);
}
}
}
private void configureScheduler(ServletContext context) {
Scheduler scheduler = (Scheduler) context.getAttribute(Constants.SCHEDULER);
if (scheduler != null) {
// Initialize
try {
scheduler.getContext().setAllowsTransientData(true);
scheduler.getContext().put("ServletContext", context);
// Give the scheduler its own connection pool... this can speed up the web-tier
// when background processing is occurring
ConnectionPool commonCP = (ConnectionPool) context.getAttribute(Constants.CONNECTION_POOL);
if (commonCP != null) {
if (!this.has(CONNECTION_POOL_MAX_SCHEDULER_CONNECTIONS)) {
scheduler.getContext().put(Constants.CONNECTION_POOL, context.getAttribute(Constants.CONNECTION_POOL));
} else {
ConnectionPool schedulerCP = new ConnectionPool();
schedulerCP.setDebug(commonCP.getDebug());
schedulerCP.setTestConnections(commonCP.getTestConnections());
schedulerCP.setAllowShrinking(commonCP.getAllowShrinking());
schedulerCP.setMaxConnections(this.get(CONNECTION_POOL_MAX_SCHEDULER_CONNECTIONS));
schedulerCP.setMaxIdleTime(commonCP.getMaxIdleTime());
schedulerCP.setMaxDeadTime(commonCP.getMaxDeadTime());
scheduler.getContext().put("ConnectionPool", schedulerCP);
}
}
ConnectionElement ce = new ConnectionElement();
ce.setDriver(this.get(CONNECTION_DRIVER));
ce.setUrl(this.get(CONNECTION_URL));
ce.setUsername(this.get(CONNECTION_USER));
ce.setPassword(this.get(CONNECTION_PASSWORD));
scheduler.getContext().put("ConnectionElement", ce);
scheduler.getContext().put("ApplicationPrefs", this);
scheduler.start();
scheduler.getContext().put(ScheduledJobs.CONTEXT_SCHEDULER_GROUP, ScheduledJobs.UNIQUE_GROUP);
ScheduledJobs.addJobs(scheduler, context);
} catch (Exception e) {
e.printStackTrace(System.out);
LOG.error("Scheduler Error: " + e.getMessage(), e);
}
}
}
private void configureWebdavManager(ServletContext context) {
LOG.info("configureWebdavManager");
WebdavManager webdavManager = (WebdavManager) context.getAttribute(Constants.WEBDAV_MANAGER);
if (webdavManager != null) {
webdavManager.setFileLibraryPath(this.get(FILE_LIBRARY_PATH));
}
}
private void configureSystemSettings(ServletContext context) {
LOG.info("configureSystemSettings");
SystemSettings systemSettings = new SystemSettings();
try {
// Load the settings...
InputStream source = null;
// Look in build.properties, or use default
String settingsFile = this.get(SYSTEM_SETTINGS_FILE);
if (settingsFile != null) {
LOG.info("SystemSettings path: " + this.get(FILE_LIBRARY_PATH) + settingsFile);
source = new FileInputStream(this.get(FILE_LIBRARY_PATH) + settingsFile);
} else {
LOG.info("SystemSettings path: /WEB-INF/settings.xml");
source = context.getResourceAsStream("/WEB-INF/settings.xml");
}
if (source != null) {
LOG.info("Loading system settings...");
XMLUtils xml = new XMLUtils(source);
systemSettings.initialize(xml.getDocumentElement());
source.close();
}
} catch (Exception e) {
e.printStackTrace(System.out);
LOG.error("System Settings Error", e);
}
context.setAttribute(Constants.SYSTEM_SETTINGS, systemSettings);
}
/**
* Description of the Method
*
* @param context Description of the Parameter
*/
public void configureDefaultBehavior(ServletContext context) {
LOG.info("Configuring default behavior...");
// Default login and session validation
if (!this.has(LOGIN_MODE)) {
this.add(LOGIN_MODE, "Default");
}
// Detect if this instance is using a legacy default, and upgrade to a theme
if (!this.has(THEME)) {
if (!this.has(JSP_TEMPLATE) || "/layoutDefault.jsp".equals(this.get(JSP_TEMPLATE))) {
this.add(THEME, "default");
this.add(COLOR_SCHEME, "dark_blue");
}
}
// Determine the site theme
if (this.has(THEME)) {
// Use a theme and its color scheme; always use the default if the theme is missing
String theme = "default";
String colorScheme = "dark_blue";
Set<String> themeFiles = context.getResourcePaths("/themes/" + this.get(THEME) + "/color-schemes");
if (themeFiles != null && themeFiles.size() > 0) {
for (String thisFile : themeFiles) {
if (thisFile.startsWith("/themes/" + this.get(THEME) + "/color-schemes/" + this.get(COLOR_SCHEME))) {
theme = this.get(THEME);
colorScheme = this.get(COLOR_SCHEME);
}
}
}
if (!theme.equals(get(THEME))) {
LOG.error("The theme (" + get(THEME) + ") and color scheme (" + get(COLOR_SCHEME) + ") could not be found, using default theme");
}
addParameter(context, Constants.TEMPLATE_THEME, theme);
addParameter(context, Constants.TEMPLATE_COLOR_SCHEME, colorScheme);
// Determine the layout (or use the default layout)
String layout = "default";
Set<String> layoutFiles = context.getResourcePaths("/themes/" + this.get(THEME) + "/jsp/");
if (layoutFiles != null && layoutFiles.size() > 0) {
for (String thisFile : layoutFiles) {
if (("/themes/" + this.get(THEME) + "/jsp/layout.jsp").equals(thisFile)) {
layout = this.get(THEME);
}
}
}
if ("default".equals(layout) && !"default".equals(this.get(THEME))) {
try {
// Check for a compiled layout
Class.forName("org.apache.jsp.themes." + JspUtils.makeJavaIdentifier(this.get(THEME)) + ".jsp.layout_jsp");
layout = this.get(THEME);
} catch (Exception e) {
LOG.info("Using default theme: " + e.getMessage());
}
}
addParameter(context, Constants.TEMPLATE_LAYOUT, "/themes/" + layout + "/jsp/layout.jsp");
LOG.info("THEME: " + get(THEME));
LOG.info(" COLOR SCHEME: " + get(COLOR_SCHEME));
LOG.info(" LAYOUT: " + "/themes/" + layout + "/jsp/layout.jsp");
} else {
// Use the specified template
addParameter(context, Constants.TEMPLATE_LAYOUT, this.get(JSP_TEMPLATE));
// Default CSS for all items on page
addParameter(context, Constants.TEMPLATE_CSS, this.get(CSS_FILE));
}
// Default color scheme for themeable items (deprecated)
if (this.has("SKIN")) {
addParameter(context, "SKIN", this.get("SKIN"));
} else {
addParameter(context, "SKIN", "blue");
this.add("SKIN", "blue");
}
// Application Settings
if (!this.has(USERS_CAN_REGISTER)) {
this.add(USERS_CAN_REGISTER, "true");
}
if (!this.has(USERS_CAN_INVITE)) {
this.add(USERS_CAN_INVITE, "true");
}
if (!this.has(SHOW_TERMS_AND_CONDITIONS)) {
this.add(SHOW_TERMS_AND_CONDITIONS, "true");
}
if (!this.has(USERS_CAN_START_PROJECTS)) {
this.add(USERS_CAN_START_PROJECTS, "false");
}
if (!this.has(USERS_ARE_ANONYMOUS)) {
this.add(USERS_ARE_ANONYMOUS, "false");
}
if (!this.has(SEARCH_USES_LOCATION)) {
this.add(SEARCH_USES_LOCATION, "true");
}
if (!this.has(SHOW_HOLIDAYS)) {
this.add(SHOW_HOLIDAYS, "true");
}
// Portal
if (!this.has(HOME_URL)) {
this.add(HOME_URL, "index.shtml");
} else if ("Portal.do?command=Default".equals(this.get(HOME_URL))) {
this.add(HOME_URL, "index.shtml");
}
if (!this.has("PORTAL")) {
this.add("PORTAL", "true");
}
if (!this.has(WEB_PAGE_TITLE)) {
this.add(WEB_PAGE_TITLE, ApplicationVersion.TITLE);
}
if (!this.has(LANGUAGE)) {
this.add(LANGUAGE, "en_US");
}
if (!this.has(TIMEZONE)) {
this.add(TIMEZONE, TimeZone.getDefault().getID());
}
if (!this.has(CURRENCY)) {
this.add(CURRENCY, NumberFormat.getCurrencyInstance().getCurrency().getCurrencyCode());
}
if (!this.has(LANGUAGES_SUPPORTED)) {
this.add(LANGUAGES_SUPPORTED, "en_US");
}
if (!this.has(MAIN_PROFILE)) {
this.add(MAIN_PROFILE, "main-profile");
}
// Dimdim service
if (!this.has(DIMDIM_ENABLED)) {
this.add(DIMDIM_ENABLED, "false");
}
if (!this.has(DIMDIM_API_DOMAIN)) {
// @note Dimdim public API is no longer available
//this.add(DIMDIM_API_DOMAIN, "http://webmeeting.dimdim.com/portal");
}
}
private void configureCache(ServletContext context) {
LOG.info("configureCache");
CacheContext cacheContext = new CacheContext();
// Give the cache manager its own connection pool... this can speed up the web-tier
// when background processing is occurring
ConnectionPool commonCP = (ConnectionPool) context.getAttribute(Constants.CONNECTION_POOL);
if (commonCP != null) {
if (!this.has(CONNECTION_POOL_MAX_CACHE_CONNECTIONS)) {
cacheContext.setConnectionPool(commonCP);
} else {
ConnectionPool cacheCP = new ConnectionPool();
cacheCP.setDebug(commonCP.getDebug());
cacheCP.setTestConnections(commonCP.getTestConnections());
cacheCP.setAllowShrinking(commonCP.getAllowShrinking());
cacheCP.setMaxConnections(this.get(CONNECTION_POOL_MAX_CACHE_CONNECTIONS));
cacheCP.setMaxIdleTime(commonCP.getMaxIdleTime());
cacheCP.setMaxDeadTime(commonCP.getMaxDeadTime());
cacheContext.setConnectionPool(cacheCP);
}
}
if (cacheContext.getConnectionPool() != null) {
// The cacheContext is ready to be finalized
ConnectionElement ce = new ConnectionElement();
ce.setDriver(this.get(CONNECTION_DRIVER));
ce.setUrl(this.get(CONNECTION_URL));
ce.setUsername(this.get(CONNECTION_USER));
ce.setPassword(this.get(CONNECTION_PASSWORD));
cacheContext.setConnectionElement(ce);
cacheContext.setApplicationPrefs(this);
cacheContext.setKey((Key) context.getAttribute(TEAM_KEY));
Caches.addCaches(cacheContext);
}
}
private void configureIndexer() {
// Determine the Lucene Indexer Context
LOG.info("Configuring Indexer...");
IndexerContext indexerContext = new IndexerContext(this);
try {
// Get the IndexerService instance... which configures it as well
IndexerFactory.getInstance().initializeIndexService(indexerContext);
} catch (Exception e) {
LOG.error("configureIndexer", e);
e.printStackTrace(System.out);
}
}
/**
* Configures freemarker for template loading
*
* @param context the servlet context to store the configuration
*/
private void configureFreemarker(ServletContext context) {
LOG.info("configureFreemarker");
try {
Configuration freemarkerConfiguration = new Configuration();
// Customized templates are stored here
File customEmailFolder = new File(get(FILE_LIBRARY_PATH) + "1" + fs + "email");
FileTemplateLoader ftl = null;
if (customEmailFolder.exists()) {
ftl = new FileTemplateLoader(customEmailFolder);
}
// Default templates are stored here
WebappTemplateLoader wtl = new WebappTemplateLoader(context, "/WEB-INF/email");
// Order the loaders
TemplateLoader[] loaders = null;
if (ftl != null) {
loaders = new TemplateLoader[]{ftl, wtl};
} else {
loaders = new TemplateLoader[]{wtl};
}
MultiTemplateLoader mtl = new MultiTemplateLoader(loaders);
freemarkerConfiguration.setTemplateLoader(mtl);
freemarkerConfiguration.setObjectWrapper(new DefaultObjectWrapper());
context.setAttribute(Constants.FREEMARKER_CONFIGURATION, freemarkerConfiguration);
} catch (Exception e) {
LOG.error("freemarker error", e);
}
}
/**
* Utility for upgrading the application
*
* @param context
*/
private void performUpgrade(ServletContext context) {
Connection db = null;
ConnectionPool commonCP = (ConnectionPool) context.getAttribute(Constants.CONNECTION_POOL);
try {
LOG.info("Upgrading the database...");
// Share the preferences with the upgrade scripts
context.setAttribute(Constants.APPLICATION_PREFS, this);
// Determine the database connection to use
ConnectionElement ce = new ConnectionElement();
ce.setDriver(this.get(CONNECTION_DRIVER));
ce.setUrl(this.get(CONNECTION_URL));
ce.setUsername(this.get(CONNECTION_USER));
ce.setPassword(this.get(CONNECTION_PASSWORD));
// Retrieve a database connection
db = commonCP.getConnection(ce, true);
// Perform the upgrade
UpgradeUtils.performUpgrade(db, context);
// Persist the new version info
save();
} catch (Exception e) {
LOG.error("performUpgrade", e);
e.printStackTrace(System.out);
} finally {
commonCP.free(db);
}
}
/**
* Saves the Application Prefs to disk
*
* @param filename Description of the Parameter
* @return Description of the Return Value
*/
public synchronized boolean save(String filename) {
try {
BufferedWriter out = new BufferedWriter(new FileWriter(filename));
out.write(GENERATED_MESSAGE + " on " + new java.util.Date() + " ###" + ls);
add("VERSION", ApplicationVersion.VERSION);
add("APP_VERSION", ApplicationVersion.APP_VERSION);
add("DB_VERSION", ApplicationVersion.DB_VERSION);
for (String param : prefs.keySet()) {
String value = prefs.get(param);
if (param.startsWith("#")) {
out.write(value + ls);
} else {
out.write(param + "=" + value + ls);
}
}
out.close();
return true;
} catch (Exception e) {
LOG.error("save", e);
return false;
}
}
/**
* Saves the properties to where they were loaded from
*
* @return Description of the Return Value
*/
public boolean save() {
if (this.has(FILE_LIBRARY_PATH)) {
return save(this.get(FILE_LIBRARY_PATH) + "build.properties");
}
return false;
}
/**
* Adds a feature to the Parameter attribute of the ApplicationPrefs object
*
* @param context The feature to be added to the Parameter attribute
* @param param The feature to be added to the Parameter attribute
* @param value The feature to be added to the Parameter attribute
*/
private void addParameter(ServletContext context, String param, String value) {
addParameter(context, param, value, null);
}
/**
* Adds a feature to the Parameter attribute of the ApplicationPrefs object
*
* @param context The feature to be added to the Parameter attribute
* @param param The feature to be added to the Parameter attribute
* @param value The feature to be added to the Parameter attribute
* @param defaultValue The feature to be added to the Parameter attribute
*/
private void addParameter(ServletContext context, String param, String value, String defaultValue) {
if (value != null) {
context.setAttribute(param, value);
} else {
if (defaultValue != null) {
context.setAttribute(param, defaultValue);
} else {
context.removeAttribute(param);
}
}
}
/**
* Save a name/value pair to the Java Preferences store
*
* @param instanceName Description of the Parameter
* @param fileLibraryLocation Description of the Parameter
* @return Description of the Return Value
*/
public static boolean saveFileLibraryLocation(String instanceName, String fileLibraryLocation) {
try {
if (instanceName == null || fileLibraryLocation == null) {
LOG.error("Invalid parameters: " + instanceName + "=" + fileLibraryLocation);
}
Preferences javaPrefs = Preferences.userNodeForPackage(ApplicationPrefs.class);
if (javaPrefs == null) {
LOG.error("Couldn't create java preferences for: " + ApplicationPrefs.class);
}
if (instanceName.length() <= Preferences.MAX_KEY_LENGTH) {
javaPrefs.put(instanceName, fileLibraryLocation);
} else {
javaPrefs.put(instanceName.substring(instanceName.length() - Preferences.MAX_KEY_LENGTH), fileLibraryLocation);
}
javaPrefs.flush();
return true;
} catch (Exception e) {
LOG.error("saveFileLibraryLocation", e);
e.printStackTrace(System.out);
return false;
}
}
/**
* Gets the configured attribute of the ApplicationPrefs object
*
* @return The configured value
*/
public boolean isConfigured() {
return (this.has(FILE_LIBRARY_PATH) && !this.has("CONFIGURING"));
}
/**
* Gets the realPath attribute of the ApplicationPrefs class
*
* @param context Description of the Parameter
* @return The realPath value
*/
public static String getRealPath(ServletContext context) {
String dir = context.getRealPath("/");
if (dir != null && !dir.endsWith(fs)) {
dir += fs;
}
return dir;
}
/**
* Gets the war attribute of the ApplicationPrefs class
*
* @param context Description of the Parameter
* @return The war value
*/
public static boolean isWar(ServletContext context) {
String realPath = context.getRealPath("/");
String fs = System.getProperty("file.separator");
if (realPath == null) {
return true;
} else if (realPath.endsWith(".war")) {
return true;
} else if (realPath.endsWith(".war" + fs)) {
return true;
} else if (realPath.indexOf("Instance") > -1) {
return true;
} else {
return false;
}
}
public void loadApplicationDictionaries(ServletContext context) {
// Load the default
String language = this.get(LANGUAGE);
if (language == null) {
language = "en_US";
}
addDictionary(context, language);
// Check for additional languages
String languages = this.get(LANGUAGES_SUPPORTED);
if (languages == null) {
return;
}
// Load additional languages
if (languages.indexOf(",") > -1) {
StringTokenizer tokenizer = new StringTokenizer(languages, ",");
while (tokenizer.hasMoreTokens()) {
String langToken = tokenizer.nextToken();
addDictionary(context, langToken);
}
} else {
if (!languages.equals(language)) {
addDictionary(context, languages);
}
}
}
public synchronized void addDictionary(ServletContext context, String language) {
if (language == null) {
LOG.error("addDictionary: language cannot be null");
} else {
if (!dictionaries.containsKey(language)) {
LOG.info("Loading dictionary: " + language);
try {
// Create a dictionary with the default language
String languagePath = "/WEB-INF/languages/";
Dictionary dictionary = new Dictionary(context, languagePath, "en_US");
if (!"en_US".equals(language)) {
// Override the text with a selected language
dictionary.load(context, languagePath, language);
}
dictionaries.put(language, dictionary);
} catch (Exception e) {
LOG.error("Language loading error (file exists?): " + e.getMessage(), e);
}
}
}
}
public String getValue(String section,
String parameter,
String tagName,
String language) {
if (null == dictionaries) {
return null;
}
final Dictionary dictionary = dictionaries.get(language);
if (null == dictionary) {
return null;
}
Map prefGroup = (Map) dictionary.getLocalizationPrefs().get(section);
if (null != prefGroup) {
Node param = (Node) prefGroup.get(parameter);
if (null != param) {
return XMLUtils.getNodeText(
XMLUtils.getFirstChild((Element) param, tagName));
}
}
return null;
}
public String getLabel(String parameter, String language) {
return getLabel("system.fields.label", parameter, language);
}
public String getLabel(String section, String parameter, String language) {
return getValue(section, parameter, "value", language);
}
public static ApplicationPrefs getApplicationPrefs(ServletContext context) {
return (ApplicationPrefs) context.getAttribute(Constants.APPLICATION_PREFS);
}
public static Configuration getFreemarkerConfiguration(ServletContext context) {
return (Configuration) context.getAttribute(Constants.FREEMARKER_CONFIGURATION);
}
}