/* * Password Management Servlets (PWM) * http://www.pwm-project.org * * Copyright (c) 2006-2009 Novell, Inc. * Copyright (c) 2009-2017 The PWM Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package password.pwm.util.localdb; import password.pwm.AppProperty; import password.pwm.PwmApplication; import password.pwm.config.Configuration; import password.pwm.error.ErrorInformation; import password.pwm.error.PwmError; import password.pwm.util.java.FileSystemUtility; import password.pwm.util.java.StringUtil; import password.pwm.util.java.TimeDuration; import password.pwm.util.logging.PwmLogger; import java.io.File; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Map; /** * @author Jason D. Rivard */ public class LocalDBFactory { // ------------------------------ FIELDS ------------------------------ private static final PwmLogger LOGGER = PwmLogger.forClass(LocalDBFactory.class); // -------------------------- STATIC METHODS -------------------------- public static synchronized LocalDB getInstance( final File dbDirectory, final boolean readonly, final PwmApplication pwmApplication, final Configuration configuration ) throws Exception { final Configuration config = (configuration == null && pwmApplication != null) ? pwmApplication.getConfig() : configuration; final long startTime = System.currentTimeMillis(); final String className; final Map<String, String> initParameters; if (config == null) { className = AppProperty.LOCALDB_IMPLEMENTATION.getDefaultValue(); final String initStrings = AppProperty.LOCALDB_INIT_STRING.getDefaultValue(); initParameters = StringUtil.convertStringListToNameValuePair(Arrays.asList(initStrings.split(";;;")), "="); } else { className = config.readAppProperty(AppProperty.LOCALDB_IMPLEMENTATION); final String initStrings = config.readAppProperty(AppProperty.LOCALDB_INIT_STRING); initParameters = StringUtil.convertStringListToNameValuePair(Arrays.asList(initStrings.split(";;;")), "="); } final Map<LocalDBProvider.Parameter,String> parameters = pwmApplication == null ? Collections.<LocalDBProvider.Parameter, String>emptyMap() : makeParameterMap(pwmApplication.getConfig(), readonly); final LocalDBProvider dbProvider = createInstance(className); LOGGER.debug("initializing " + className + " localDBProvider instance"); final LocalDB localDB = new LocalDBAdaptor(dbProvider, pwmApplication); initInstance(dbProvider, dbDirectory, initParameters, className, parameters); final TimeDuration openTime = new TimeDuration(System.currentTimeMillis() - startTime); if (!readonly) { LOGGER.trace("clearing TEMP db"); localDB.truncate(LocalDB.DB.TEMP); final LocalDBUtility localDBUtility = new LocalDBUtility(localDB); if (localDBUtility.readImportInprogressFlag()) { LOGGER.error("previous database import process did not complete successfully, clearing all data"); localDBUtility.prepareForImport(); localDBUtility.markImportComplete(); } } final StringBuilder debugText = new StringBuilder(); debugText.append("LocalDB open in ").append(openTime.asCompactString()); debugText.append(", db size: ").append(StringUtil.formatDiskSize(FileSystemUtility.getFileDirectorySize(localDB.getFileLocation()))); debugText.append(" at ").append(dbDirectory.toString()); final long freeSpace = FileSystemUtility.diskSpaceRemaining(localDB.getFileLocation()); if (freeSpace >= 0) { debugText.append(", ").append(StringUtil.formatDiskSize(freeSpace)).append(" free"); } LOGGER.info(debugText); return localDB; } private static LocalDBProvider createInstance(final String className) throws Exception { final LocalDBProvider localDB; try { final Class c = Class.forName(className); final Object impl = c.newInstance(); if (!(impl instanceof LocalDBProvider)) { throw new Exception("unable to createSharedHistoryManager new LocalDB, " + className + " is not instance of " + LocalDBProvider.class.getName()); } localDB = (LocalDBProvider) impl; } catch (Throwable e) { final String errorMsg = "error creating new LocalDB instance: " + e.getClass().getName() + ":" + e.getMessage(); LOGGER.error(errorMsg,e); throw new LocalDBException(new ErrorInformation(PwmError.ERROR_LOCALDB_UNAVAILABLE, errorMsg)); } return localDB; } private static void initInstance( final LocalDBProvider pwmDBProvider, final File dbFileLocation, final Map<String, String> initParameters, final String theClass, final Map<LocalDBProvider.Parameter,String> parameters ) throws Exception { try { if (dbFileLocation.mkdir()) { LOGGER.trace("created directory at " + dbFileLocation.getAbsolutePath()); } pwmDBProvider.init(dbFileLocation, initParameters, parameters); } catch (Exception e) { final String errorMsg = "error creating new LocalDB instance: " + e.getClass().getName() + ":" + e.getMessage(); LOGGER.error(errorMsg,e); throw new LocalDBException(new ErrorInformation(PwmError.ERROR_LOCALDB_UNAVAILABLE, errorMsg)); } LOGGER.trace("db init completed for " + theClass); } private static Map<LocalDBProvider.Parameter, String> makeParameterMap(final Configuration configuration, final boolean readOnly) { final Map<LocalDBProvider.Parameter,String> parameters = new HashMap<>(); if (readOnly) { parameters.put(LocalDBProvider.Parameter.readOnly, Boolean.TRUE.toString()); } if (Boolean.parseBoolean(configuration.readAppProperty(AppProperty.LOCALDB_AGGRESSIVE_COMPACT_ENABLED))) { parameters.put(LocalDBProvider.Parameter.aggressiveCompact, Boolean.TRUE.toString()); } return Collections.unmodifiableMap(parameters); } }