/**
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, version 2.1, dated February 1999.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the latest version of the GNU Lesser General
 * Public License as published by the Free Software Foundation;
 *
 * 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.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program (LICENSE.txt); if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package org.jamwiki.servlets;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.jamwiki.DataAccessException;
import org.jamwiki.Environment;
import org.jamwiki.WikiBase;
import org.jamwiki.WikiConfiguration;
import org.jamwiki.WikiException;
import org.jamwiki.WikiMessage;
import org.jamwiki.authentication.WikiUserDetailsImpl;
import org.jamwiki.db.WikiDatabase;
import org.jamwiki.model.Role;
import org.jamwiki.model.WikiConfigurationObject;
import org.jamwiki.model.WikiUser;
import org.jamwiki.utils.Encryption;
import org.jamwiki.utils.SpamFilter;
import org.jamwiki.utils.WikiCache;
import org.jamwiki.utils.WikiLogger;
import org.jamwiki.utils.WikiUtil;
import org.springframework.web.servlet.ModelAndView;

/**
 * Used to provide administrative functions including changing Wiki
 * configuration settings and refreshing internal Wiki objects.
 */
public class AdminServlet extends JAMWikiServlet {

	private static final WikiLogger logger = WikiLogger.getLogger(AdminServlet.class.getName());
	/** The name of the JSP file used to render the servlet output for the admin maintenance configuration. */
	protected static final String JSP_ADMIN = "admin.jsp";
	/** The name of the JSP file used to render the servlet output for the admin maintenance functionality. */
	protected static final String JSP_ADMIN_SYSTEM = "admin-maintenance.jsp";

	/**
	 * This method handles the request after its parent class receives control.
	 *
	 * @param request - Standard HttpServletRequest object.
	 * @param response - Standard HttpServletResponse object.
	 * @return A <code>ModelAndView</code> object to be handled by the rest of the Spring framework.
	 */
	protected ModelAndView handleJAMWikiRequest(HttpServletRequest request, HttpServletResponse response, ModelAndView next, WikiPageInfo pageInfo) throws Exception {
		String function = request.getParameter("function");
		next.addObject("function", function);
		if (StringUtils.isBlank(function) && ServletUtil.isTopic(request, "Special:Maintenance")) {
			viewAdminSystem(request, next, pageInfo);
		} else if (StringUtils.isBlank(function)) {
			viewAdmin(request, next, pageInfo, null);
		} else if (function.equals("cache")) {
			cache(request, next, pageInfo);
		} else if (function.equals("search")) {
			refreshIndex(request, next, pageInfo);
		} else if (function.equals("properties")) {
			properties(request, next, pageInfo);
		} else if (function.equals("logitems")) {
			logItems(request, next, pageInfo);
		} else if (function.equals("recentchanges")) {
			recentChanges(request, next, pageInfo);
		} else if (function.equals("spam")) {
			spam(request, next, pageInfo);
		} else if (function.equals("migrate")) {
			migrateDatabase(request, next, pageInfo);
		} else if (function.equals("password")) {
			password(request, next, pageInfo);
		} else if (function.equals("adduser")) {
			adduser(request, next, pageInfo);
		} else if (function.equals("namespaces")) {
			namespaces(request, next, pageInfo);
		}
		return next;
	}

	/**
	 * add new user account
	 */
	private void adduser(HttpServletRequest request, ModelAndView next, WikiPageInfo pageInfo) throws Exception {
		List<WikiMessage> errors = new ArrayList<WikiMessage>();
		String userLogin = request.getParameter("adduserLogin");
		String password = request.getParameter("adduserPassword");
		String confirmPassword = request.getParameter("adduserPasswordConfirm");
		String email = request.getParameter("adduserEmail");
		String displayName = request.getParameter("adduserdisplayName");
		try {
			WikiUser user = WikiBase.getDataHandler().lookupWikiUser(userLogin);
			if (user != null) {
				throw new WikiException(new WikiMessage("admin.adduser.message.uidexists", userLogin));
			}
			WikiUtil.validatePassword(password, confirmPassword);
			String encryptedPassword = Encryption.encrypt(password);
			user = new WikiUser(userLogin);
			user.setDisplayName(displayName);
			user.setEmail(email);
			user.setCreateIpAddress(ServletUtil.getIpAddress(request));
			user.setLastLoginIpAddress(ServletUtil.getIpAddress(request));
			WikiBase.getDataHandler().writeWikiUser(user, userLogin, encryptedPassword);
		} catch (WikiException e) {
			errors.add(e.getWikiMessage());
		} catch (Exception e) {
			logger.severe("Failure while create new user account", e);
			errors.add(new WikiMessage("admin.message.adduserfail", e.getMessage()));
		}
		if (!errors.isEmpty()) {
			next.addObject("errors", errors);
			next.addObject("adduserLogin", userLogin);
			next.addObject("adduserPassword", password);
			next.addObject("adduserPasswordConfirm", confirmPassword);
			next.addObject("adduserEmail", email);
			next.addObject("adduserdisplayName", displayName);
		} else {
			next.addObject("message", new WikiMessage("admin.adduser.message.success", userLogin));
		}
		viewAdminSystem(request, next, pageInfo);
	}

	/**
	 *
	 */
	private void cache(HttpServletRequest request, ModelAndView next, WikiPageInfo pageInfo) throws Exception {
		try {
			WikiCache.initialize();
			next.addObject("message", new WikiMessage("admin.message.cache"));
		} catch (Exception e) {
			logger.severe("Failure while clearing cache", e);
			List<WikiMessage> errors = new ArrayList<WikiMessage>();
			errors.add(new WikiMessage("admin.cache.message.clearfailed", e.getMessage()));
			next.addObject("errors", errors);
		}
		viewAdminSystem(request, next, pageInfo);
	}

	/**
	 *
	 */
	private void logItems(HttpServletRequest request, ModelAndView next, WikiPageInfo pageInfo) throws Exception {
		try {
			WikiBase.getDataHandler().reloadLogItems();
			next.addObject("message", new WikiMessage("admin.message.logitems"));
		} catch (Exception e) {
			logger.severe("Failure while loading log items", e);
			List<WikiMessage> errors = new ArrayList<WikiMessage>();
			errors.add(new WikiMessage("admin.message.logitemsfail", e.getMessage()));
			next.addObject("errors", errors);
		}
		viewAdminSystem(request, next, pageInfo);
	}

	/**
	 *
	 */
	private void migrateDatabase(HttpServletRequest request, ModelAndView next, WikiPageInfo pageInfo) throws Exception {
		List<WikiMessage> errors = new ArrayList<WikiMessage>();
		Properties props = new Properties();
		try {
			setProperty(props, request, Environment.PROP_BASE_PERSISTENCE_TYPE);
			if (props.getProperty(Environment.PROP_BASE_PERSISTENCE_TYPE).equals(WikiBase.PERSISTENCE_EXTERNAL)) {
				setProperty(props, request, Environment.PROP_DB_DRIVER);
				setProperty(props, request, Environment.PROP_DB_TYPE);
				setProperty(props, request, Environment.PROP_DB_URL);
				setProperty(props, request, Environment.PROP_DB_USERNAME);
				setPassword(props, request, next, Environment.PROP_DB_PASSWORD, "dbPassword");
			} else {
				// reverting from external database to an internal database
				props.setProperty(Environment.PROP_BASE_FILE_DIR, Environment.getValue(Environment.PROP_BASE_FILE_DIR));
				WikiDatabase.setupDefaultDatabase(props);
			}
			// migrate from the current database to the new database
			// identified by the properties
			// Will return errors if the new database cannot be connected to,
			// if it is already populated, or an error occurs copying the contents
			WikiDatabase.migrateDatabase(props, errors);
			if (this.saveProperties(request, next, pageInfo, props, errors)) {
				next.addObject("message", new WikiMessage("admin.message.migratedatabase", Environment.getValue(Environment.PROP_DB_URL)));
			}
		} catch (Exception e) {
			logger.severe("Failure while migrating to a new database", e);
			errors.add(new WikiMessage("admin.message.migrationfailure", e.getMessage()));
		}
		next.addObject("errors", errors);
		viewAdminSystem(request, next, pageInfo);
	}

	/**
	 *
	 */
	private void namespaces(HttpServletRequest request, ModelAndView next, WikiPageInfo pageInfo) {
		try {
			int numUpdated = WikiDatabase.fixIncorrectTopicNamespaces();
			next.addObject("message", new WikiMessage("admin.maintenance.message.namespaces", Integer.toString(numUpdated)));
		} catch (DataAccessException e) {
			logger.severe("Failure while fixing incorrect topic namespaces", e);
			List<WikiMessage> errors = new ArrayList<WikiMessage>();
			errors.add(new WikiMessage("admin.maintenance.error.namespacefail", e.getMessage()));
			next.addObject("errors", errors);
		}
		viewAdminSystem(request, next, pageInfo);
	}

	/**
	 *
	 */
	private void password(HttpServletRequest request, ModelAndView next, WikiPageInfo pageInfo) throws Exception {
		List<WikiMessage> errors = new ArrayList<WikiMessage>();
		String userLogin = request.getParameter("passwordLogin");
		String newPassword = request.getParameter("passwordPassword");
		String confirmPassword = request.getParameter("passwordPasswordConfirm");
		try {
			WikiUser user = WikiBase.getDataHandler().lookupWikiUser(userLogin);
			if (user == null) {
				throw new WikiException(new WikiMessage("admin.password.message.invalidlogin", userLogin));
			}
			WikiUtil.validatePassword(newPassword, confirmPassword);
			String encryptedPassword = Encryption.encrypt(newPassword);
			WikiBase.getDataHandler().writeWikiUser(user, userLogin, encryptedPassword);
		} catch (WikiException e) {
			errors.add(e.getWikiMessage());
		} catch (Exception e) {
			logger.severe("Failure while updating user password", e);
			errors.add(new WikiMessage("error.unknown", e.getMessage()));
		}
		if (!errors.isEmpty()) {
			next.addObject("errors", errors);
			next.addObject("passwordLogin", userLogin);
			next.addObject("passwordPassword", newPassword);
			next.addObject("passwordPasswordConfirm", confirmPassword);
		} else {
			next.addObject("message", new WikiMessage("admin.password.message.success", userLogin));
		}
		viewAdminSystem(request, next, pageInfo);
	}

	private void properties(HttpServletRequest request, ModelAndView next, WikiPageInfo pageInfo) throws Exception {
		Properties props = new Properties();
		List<WikiMessage> errors = new ArrayList<WikiMessage>();
		try {
			setProperty(props, request, Environment.PROP_SERVER_URL);
			setProperty(props, request, Environment.PROP_SITE_NAME);
			setProperty(props, request, Environment.PROP_BASE_DEFAULT_TOPIC);
			setProperty(props, request, Environment.PROP_BASE_LOGO_IMAGE);
			setProperty(props, request, Environment.PROP_BASE_META_DESCRIPTION);
			setProperty(props, request, Environment.PROP_TOPIC_EDITOR);
			setNumericProperty(props, request, Environment.PROP_IMAGE_RESIZE_INCREMENT, errors);
			setNumericProperty(props, request, Environment.PROP_MAX_TOPIC_VERSION_EXPORT, errors);
			setNumericProperty(props, request, Environment.PROP_RECENT_CHANGES_NUM, errors);
			setBooleanProperty(props, request, Environment.PROP_TOPIC_SPAM_FILTER);
			setBooleanProperty(props, request, Environment.PROP_TOPIC_USE_PREVIEW);
			setBooleanProperty(props, request, Environment.PROP_TOPIC_USE_SHOW_CHANGES);
			setBooleanProperty(props, request, Environment.PROP_PRINT_NEW_WINDOW);
			setBooleanProperty(props, request, Environment.PROP_EXTERNAL_LINK_NEW_WINDOW);
			setProperty(props, request, Environment.PROP_BASE_SEARCH_ENGINE);
			setProperty(props, request, Environment.PROP_PARSER_CLASS);
			setBooleanProperty(props, request, Environment.PROP_PARSER_TOC);
			setNumericProperty(props, request, Environment.PROP_PARSER_TOC_DEPTH, errors);
			setBooleanProperty(props, request, Environment.PROP_PARSER_ALLOW_HTML);
			setBooleanProperty(props, request, Environment.PROP_PARSER_ALLOW_JAVASCRIPT);
			setBooleanProperty(props, request, Environment.PROP_PARSER_ALLOW_TEMPLATES);
			setProperty(props, request, Environment.PROP_PARSER_SIGNATURE_USER_PATTERN);
			setProperty(props, request, Environment.PROP_PARSER_SIGNATURE_DATE_PATTERN);
			setProperty(props, request, Environment.PROP_BASE_FILE_DIR);
			setProperty(props, request, Environment.PROP_BASE_PERSISTENCE_TYPE);
			if (props.getProperty(Environment.PROP_BASE_PERSISTENCE_TYPE).equals(WikiBase.PERSISTENCE_EXTERNAL)) {
				setProperty(props, request, Environment.PROP_DB_DRIVER);
				setProperty(props, request, Environment.PROP_DB_TYPE);
				setProperty(props, request, Environment.PROP_DB_URL);
				setProperty(props, request, Environment.PROP_DB_USERNAME);
				setPassword(props, request, next, Environment.PROP_DB_PASSWORD, "dbPassword");
			} else {
				WikiDatabase.setupDefaultDatabase(props);
			}
			setNumericProperty(props, request, Environment.PROP_DBCP_MAX_ACTIVE, errors);
			setNumericProperty(props, request, Environment.PROP_DBCP_MAX_IDLE, errors);
			setBooleanProperty(props, request, Environment.PROP_DBCP_TEST_ON_BORROW);
			setBooleanProperty(props, request, Environment.PROP_DBCP_TEST_ON_RETURN);
			setBooleanProperty(props, request, Environment.PROP_DBCP_TEST_WHILE_IDLE);
			setNumericProperty(props, request, Environment.PROP_DBCP_MIN_EVICTABLE_IDLE_TIME, errors);
			setNumericProperty(props, request, Environment.PROP_DBCP_TIME_BETWEEN_EVICTION_RUNS, errors);
			setNumericProperty(props, request, Environment.PROP_DBCP_NUM_TESTS_PER_EVICTION_RUN, errors);
			setProperty(props, request, Environment.PROP_DBCP_WHEN_EXHAUSTED_ACTION);
			String maxFileSizeString = request.getParameter(Environment.PROP_FILE_MAX_FILE_SIZE);
			if (StringUtils.isBlank(maxFileSizeString) || !StringUtils.isNumeric(maxFileSizeString)) {
				errors.add(new WikiMessage("admin.message.nonnumeric", Environment.PROP_FILE_MAX_FILE_SIZE, maxFileSizeString));
			} else {
				long maxFileSizeInKB = Long.parseLong(maxFileSizeString);
				props.setProperty(Environment.PROP_FILE_MAX_FILE_SIZE, Long.toString(maxFileSizeInKB * 1000));
			}
			setProperty(props, request, Environment.PROP_FILE_DIR_FULL_PATH);
			setProperty(props, request, Environment.PROP_FILE_DIR_RELATIVE_PATH);
			setProperty(props, request, Environment.PROP_FILE_SERVER_URL);
			setProperty(props, request, Environment.PROP_FILE_BLACKLIST_TYPE);
			setProperty(props, request, Environment.PROP_FILE_BLACKLIST);
			setProperty(props, request, Environment.PROP_FILE_WHITELIST);
			/*
			setProperty(props, request, Environment.PROP_EMAIL_SMTP_HOST);
			setProperty(props, request, Environment.PROP_EMAIL_SMTP_USERNAME);
			setPassword(props, request, next, Environment.PROP_EMAIL_SMTP_PASSWORD, "smtpPassword");
			setProperty(props, request, Environment.PROP_EMAIL_REPLY_ADDRESS);
			*/
			setNumericProperty(props, request, Environment.PROP_CACHE_INDIVIDUAL_SIZE, errors);
			setNumericProperty(props, request, Environment.PROP_CACHE_MAX_AGE, errors);
			setNumericProperty(props, request, Environment.PROP_CACHE_MAX_IDLE_AGE, errors);
			setNumericProperty(props, request, Environment.PROP_CACHE_TOTAL_SIZE, errors);
			setBooleanProperty(props, request, Environment.PROP_RSS_ALLOWED);
			setProperty(props, request, Environment.PROP_RSS_TITLE);
			errors.addAll(ServletUtil.validateSystemSettings(props));
			if (this.saveProperties(request, next, pageInfo, props, errors)) {
				next.addObject("message", new WikiMessage("admin.message.changessaved"));
			}
		} catch (Exception e) {
			logger.severe("Failure while processing property values", e);
			errors.add(new WikiMessage("admin.message.propertyfailure", e.getMessage()));
		}
		next.addObject("errors", errors);
		viewAdmin(request, next, pageInfo, props);
	}

	/**
	 *
	 */
	private void recentChanges(HttpServletRequest request, ModelAndView next, WikiPageInfo pageInfo) throws Exception {
		try {
			WikiBase.getDataHandler().reloadRecentChanges();
			next.addObject("message", new WikiMessage("admin.message.recentchanges"));
		} catch (Exception e) {
			logger.severe("Failure while loading recent changes", e);
			List<WikiMessage> errors = new ArrayList<WikiMessage>();
			errors.add(new WikiMessage("admin.message.recentchangesfail", e.getMessage()));
			next.addObject("errors", errors);
		}
		viewAdminSystem(request, next, pageInfo);
	}

	/**
	 *
	 */
	private void refreshIndex(HttpServletRequest request, ModelAndView next, WikiPageInfo pageInfo) throws Exception {
		try {
			WikiBase.getSearchEngine().refreshIndex();
			next.addObject("message", new WikiMessage("admin.message.indexrefreshed"));
		} catch (Exception e) {
			logger.severe("Failure while refreshing search index", e);
			List<WikiMessage> errors = new ArrayList<WikiMessage>();
			errors.add(new WikiMessage("admin.message.searchrefresh", e.getMessage()));
			next.addObject("errors", errors);
		}
		viewAdminSystem(request, next, pageInfo);
	}

	/**
	 *
	 */
	private boolean saveProperties(HttpServletRequest request, ModelAndView next, WikiPageInfo pageInfo, Properties props, List<WikiMessage> errors) throws Exception {
		if (!errors.isEmpty()) {
			next.addObject("message", new WikiMessage("admin.message.changesnotsaved"));
			return false;
		}
		// all is well, save the properties
		Iterator iterator = props.keySet().iterator();
		while (iterator.hasNext()) {
			String key = (String)iterator.next();
			String value = props.getProperty(key);
			Environment.setValue(key, value);
		}
		Environment.saveProperties();
		// re-initialize to reset database settings (if needed)
		WikiUserDetailsImpl userDetails = ServletUtil.currentUserDetails();
		if (userDetails.hasRole(Role.ROLE_ANONYMOUS)) {
			throw new IllegalArgumentException("Cannot pass null or anonymous WikiUser object to setupAdminUser");
		}
		WikiUser user = ServletUtil.currentWikiUser();
		WikiBase.reset(request.getLocale(), user, user.getUsername(), null);
		return true;
	}

	/**
	 *
	 */
	private static void setBooleanProperty(Properties props, HttpServletRequest request, String parameter) {
		boolean value = (request.getParameter(parameter) != null);
		props.setProperty(parameter, Boolean.toString(value));
	}

	/**
	 *
	 */
	private static void setPassword(Properties props, HttpServletRequest request, ModelAndView next, String parameter, String passwordParam) throws Exception {
		String value = request.getParameter(parameter);
		if (!StringUtils.isBlank(value)) {
			Encryption.setEncryptedProperty(parameter, value, props);
			next.addObject(passwordParam, request.getParameter(parameter));
		} else {
			props.setProperty(parameter, Environment.getValue(parameter));
		}
	}

	/**
	 *
	 */
	private static void setNumericProperty(Properties props, HttpServletRequest request, String parameter, List<WikiMessage> errors) {
		String value = request.getParameter(parameter);
		if (StringUtils.isBlank(value) || !StringUtils.isNumeric(value)) {
			errors.add(new WikiMessage("admin.message.nonnumeric", parameter, value));
		}
		props.setProperty(parameter, value);
	}

	/**
	 *
	 */
	private static void setProperty(Properties props, HttpServletRequest request, String parameter) {
		String value = request.getParameter(parameter);
		if (value == null) {
			value = "";
		}
		props.setProperty(parameter, value);
	}

	/**
	 *
	 */
	private void spam(HttpServletRequest request, ModelAndView next, WikiPageInfo pageInfo) throws Exception {
		try {
			SpamFilter.reload();
			next.addObject("message", new WikiMessage("admin.message.spamfilter"));
		} catch (Exception e) {
			logger.severe("Failure while reloading spam filter patterns", e);
			List<WikiMessage> errors = new ArrayList<WikiMessage>();
			errors.add(new WikiMessage("admin.message.spamfilterfail", e.getMessage()));
			next.addObject("errors", errors);
		}
		viewAdminSystem(request, next, pageInfo);
	}

	/**
	 *
	 */
	private void viewAdmin(HttpServletRequest request, ModelAndView next, WikiPageInfo pageInfo, Properties props) {
		pageInfo.setContentJsp(JSP_ADMIN);
		pageInfo.setAdmin(true);
		pageInfo.setPageTitle(new WikiMessage("admin.title"));
		Map<String, String> editors = WikiConfiguration.getInstance().getEditors();
		next.addObject("editors", editors);
		List<WikiConfigurationObject> dataHandlers = WikiConfiguration.getInstance().getDataHandlers();
		next.addObject("dataHandlers", dataHandlers);
		List<WikiConfigurationObject> searchEngines = WikiConfiguration.getInstance().getSearchEngines();
		next.addObject("searchEngines", searchEngines);
		List<WikiConfigurationObject> parsers = WikiConfiguration.getInstance().getParsers();
		next.addObject("parsers", parsers);
		LinkedHashMap<Integer, String> poolExhaustedMap = new LinkedHashMap<Integer, String>();
		poolExhaustedMap.put(Integer.valueOf(GenericObjectPool.WHEN_EXHAUSTED_FAIL), "admin.persistence.caption.whenexhaustedaction.fail");
		poolExhaustedMap.put(Integer.valueOf(GenericObjectPool.WHEN_EXHAUSTED_BLOCK), "admin.persistence.caption.whenexhaustedaction.block");
		poolExhaustedMap.put(Integer.valueOf(GenericObjectPool.WHEN_EXHAUSTED_GROW), "admin.persistence.caption.whenexhaustedaction.grow");
		next.addObject("poolExhaustedMap", poolExhaustedMap);
		LinkedHashMap<Integer, String> blacklistTypesMap = new LinkedHashMap<Integer, String>();
		blacklistTypesMap.put(Integer.valueOf(WikiBase.UPLOAD_ALL), "admin.upload.caption.allowall");
		blacklistTypesMap.put(Integer.valueOf(WikiBase.UPLOAD_NONE), "admin.upload.caption.allownone");
		blacklistTypesMap.put(Integer.valueOf(WikiBase.UPLOAD_BLACKLIST), "admin.upload.caption.useblacklist");
		blacklistTypesMap.put(Integer.valueOf(WikiBase.UPLOAD_WHITELIST), "admin.upload.caption.usewhitelist");
		next.addObject("blacklistTypes", blacklistTypesMap);
		if (props == null) {
			props = Environment.getInstance();
		}
		long maximumFileSize = Long.valueOf(props.getProperty(Environment.PROP_FILE_MAX_FILE_SIZE))/1000;
		next.addObject("maximumFileSize", maximumFileSize);
		next.addObject("props", props);
	}

	/**
	 *
	 */
	private void viewAdminSystem(HttpServletRequest request, ModelAndView next, WikiPageInfo pageInfo) {
		pageInfo.setContentJsp(JSP_ADMIN_SYSTEM);
		pageInfo.setAdmin(true);
		pageInfo.setPageTitle(new WikiMessage("admin.maintenance.title"));
		boolean allowExport = Environment.getValue(Environment.PROP_BASE_PERSISTENCE_TYPE).equals(WikiBase.PERSISTENCE_INTERNAL);
		next.addObject("allowExport", allowExport);
		List<WikiConfigurationObject> dataHandlers = WikiConfiguration.getInstance().getDataHandlers();
		next.addObject("dataHandlers", dataHandlers);
	}
}
