Java tutorial
/* ================================================================== * CASettingsService.java - Mar 12, 2012 1:11:29 PM * * Copyright 2007-2012 SolarNetwork.net Dev Team * * 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 net.solarnetwork.node.settings.ca; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileFilter; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.Dictionary; import java.util.EnumSet; import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.solarnetwork.node.Setting; import net.solarnetwork.node.Setting.SettingFlag; import net.solarnetwork.node.backup.BackupResource; import net.solarnetwork.node.backup.BackupResourceProvider; import net.solarnetwork.node.backup.ResourceBackupResource; import net.solarnetwork.node.dao.BasicBatchOptions; import net.solarnetwork.node.dao.BatchableDao.BatchCallback; import net.solarnetwork.node.dao.BatchableDao.BatchCallbackResult; import net.solarnetwork.node.dao.SettingDao; import net.solarnetwork.node.settings.FactorySettingSpecifierProvider; import net.solarnetwork.node.settings.KeyedSettingSpecifier; import net.solarnetwork.node.settings.SettingSpecifier; import net.solarnetwork.node.settings.SettingSpecifierProvider; import net.solarnetwork.node.settings.SettingSpecifierProviderFactory; import net.solarnetwork.node.settings.SettingValueBean; import net.solarnetwork.node.settings.SettingsBackup; import net.solarnetwork.node.settings.SettingsCommand; import net.solarnetwork.node.settings.SettingsImportOptions; import net.solarnetwork.node.settings.SettingsService; import net.solarnetwork.node.settings.support.BasicFactorySettingSpecifierProvider; import net.solarnetwork.node.support.KeyValuePair; import org.osgi.framework.Constants; import org.osgi.framework.InvalidSyntaxException; import org.osgi.service.cm.Configuration; import org.osgi.service.cm.ConfigurationAdmin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.ByteArrayResource; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; import org.supercsv.cellprocessor.ConvertNullTo; import org.supercsv.cellprocessor.ift.CellProcessor; import org.supercsv.io.CsvBeanReader; import org.supercsv.io.CsvBeanWriter; import org.supercsv.io.ICsvBeanReader; import org.supercsv.io.ICsvBeanWriter; import org.supercsv.prefs.CsvPreference; import org.supercsv.util.CsvContext; /** * Implementation of {@link SettingsService} that uses * {@link ConfigurationAdmin} to change settings at runtime, and * {@link SettingDao} to persist changes between application restarts. * * <p> * The configurable properties of this class are: * </p> * * <dl class="class-properties"> * <dt>configurationAdmin</dt> * <dd>The {@link ConfigurationAdmin} service to use.</dd> * </dl> * * @author matt * @version 1.2 */ public class CASettingsService implements SettingsService, BackupResourceProvider { /** The OSGi service property key for the setting PID. */ public static final String OSGI_PROPERTY_KEY_SETTING_PID = "settingPid"; private static final String OSGI_PROPERTY_KEY_FACTORY_INSTANCE_KEY = CASettingsService.class.getName() + ".FACTORY_INSTANCE_KEY"; private static final String SETTING_LAST_BACKUP_DATE = "solarnode.settings.lastBackupDate"; private static final String BACKUP_DATE_FORMAT = "yyyy-MM-dd-HHmmss"; private static final String BACKUP_FILENAME_PREFIX = "settings_"; private static final String BACKUP_FILENAME_EXT = "txt"; private static final Pattern BACKUP_FILENAME_PATTERN = Pattern .compile('^' + BACKUP_FILENAME_PREFIX + "(\\d{4}-\\d{2}-\\d{2}-\\d{6})\\." + BACKUP_FILENAME_EXT + "$"); private static final int DEFAULT_BACKUP_MAX_COUNT = 5; private ConfigurationAdmin configurationAdmin; private SettingDao settingDao; private TransactionTemplate transactionTemplate; private String backupDestinationPath; private int backupMaxCount = DEFAULT_BACKUP_MAX_COUNT; private final Map<String, FactoryHelper> factories = new TreeMap<String, FactoryHelper>(); // private final Map<String, SettingSpecifierProviderFactory> factories = // new TreeMap<String, SettingSpecifierProviderFactory>(); // private final Map<String, List<SettingSpecifierProvider>> // factoryProviders = new HashMap<String, List<SettingSpecifierProvider>>(); private final Map<String, SettingSpecifierProvider> providers = new TreeMap<String, SettingSpecifierProvider>(); private final Logger log = LoggerFactory.getLogger(getClass()); private String getFactorySettingKey(String factoryPid) { return factoryPid + ".FACTORY"; } private String getFactoryInstanceSettingKey(String factoryPid, String instanceKey) { return factoryPid + (instanceKey == null ? "" : "." + instanceKey); } /** * Callback when a {@link SettingSpecifierProviderFactory} has been * registered. * * @param provider * the provider object * @param properties * the service properties */ public void onBindFactory(SettingSpecifierProviderFactory provider, Map<String, ?> properties) { log.debug("Bind called on factory {} with props {}", provider, properties); final String factoryPid = provider.getFactoryUID(); synchronized (factories) { factories.put(factoryPid, new FactoryHelper(provider)); // find all configured factory instances, and publish those // configurations now. First we look up all registered factory // instances, so each returned result returns a configured instance // key List<KeyValuePair> instanceKeys = settingDao.getSettings(getFactorySettingKey(factoryPid)); for (KeyValuePair instanceKey : instanceKeys) { SettingsCommand cmd = new SettingsCommand(); cmd.setProviderKey(factoryPid); cmd.setInstanceKey(instanceKey.getKey()); // now lookup all settings for the configured instance List<KeyValuePair> settings = settingDao .getSettings(getFactoryInstanceSettingKey(factoryPid, instanceKey.getKey())); for (KeyValuePair setting : settings) { SettingValueBean bean = new SettingValueBean(); bean.setKey(setting.getKey()); bean.setValue(setting.getValue()); cmd.getValues().add(bean); } updateSettings(cmd); } } } /** * Callback when a {@link SettingSpecifierProviderFactory} has been * un-registered. * * @param config * the configuration object * @param properties * the service properties */ public void onUnbindFactory(SettingSpecifierProviderFactory provider, Map<String, ?> properties) { if (provider == null) { // gemini blueprint calls this when availability="optional" and there are no services return; } log.debug("Unbind called on factory {} with props {}", provider, properties); final String pid = provider.getFactoryUID(); synchronized (factories) { factories.remove(pid); } } /** * Callback when a {@link SettingSpecifierProvider} has been registered. * * @param provider * the provider object * @param properties * the service properties */ public void onBind(SettingSpecifierProvider provider, Map<String, ?> properties) { log.debug("Bind called on {} with props {}", provider, properties); final String pid = provider.getSettingUID(); List<SettingSpecifierProvider> factoryList = null; String factoryInstanceKey = null; synchronized (factories) { FactoryHelper helper = factories.get(pid); if (helper != null) { // Note: SERVICE_PID not normally provided by Spring: requires // custom SN implementation bundle String instancePid = (String) properties.get(Constants.SERVICE_PID); Configuration conf; try { conf = configurationAdmin.getConfiguration(instancePid, null); @SuppressWarnings("unchecked") Dictionary<String, ?> props = conf.getProperties(); if (props != null) { factoryInstanceKey = (String) props.get(OSGI_PROPERTY_KEY_FACTORY_INSTANCE_KEY); log.debug("Got factory {} instance key {}", pid, factoryInstanceKey); factoryList = helper.getInstanceProviders(factoryInstanceKey); factoryList.add(provider); } } catch (IOException e) { log.error("Error getting factory instance configuration {}", instancePid, e); } } } if (factoryList == null) { synchronized (providers) { providers.put(pid, provider); } } final String settingKey = getFactoryInstanceSettingKey(pid, factoryInstanceKey); List<KeyValuePair> settings = settingDao.getSettings(settingKey); if (settings.size() < 1) { return; } SettingsCommand cmd = new SettingsCommand(); for (KeyValuePair pair : settings) { SettingValueBean bean = new SettingValueBean(); bean.setProviderKey(provider.getSettingUID()); bean.setInstanceKey(factoryInstanceKey); bean.setKey(pair.getKey()); bean.setValue(pair.getValue()); cmd.getValues().add(bean); } updateSettings(cmd); } /** * Callback when a {@link SettingSpecifierProvider} has been un-registered. * * @param config * the configuration object * @param properties * the service properties */ public void onUnbind(SettingSpecifierProvider provider, Map<String, ?> properties) { if (provider == null) { // gemini blueprint calls this when availability="optional" and there are no services return; } log.debug("Unbind called on {} with props {}", provider, properties); final String pid = provider.getSettingUID(); synchronized (factories) { FactoryHelper helper = factories.get(pid); if (helper != null) { helper.removeProvider(provider); return; } } synchronized (providers) { providers.remove(pid); } } @Override public List<SettingSpecifierProvider> getProviders() { synchronized (providers) { return new ArrayList<SettingSpecifierProvider>(providers.values()); } } @Override public List<SettingSpecifierProviderFactory> getProviderFactories() { List<SettingSpecifierProviderFactory> results; synchronized (factories) { results = new ArrayList<SettingSpecifierProviderFactory>(factories.size()); for (FactoryHelper helper : factories.values()) { results.add(helper.getFactory()); } return results; } } @Override public SettingSpecifierProviderFactory getProviderFactory(String factoryUID) { synchronized (factories) { FactoryHelper helper = factories.get(factoryUID); if (helper != null) { return helper.getFactory(); } return null; } } @Override public Map<String, List<FactorySettingSpecifierProvider>> getProvidersForFactory(String factoryUID) { Map<String, List<FactorySettingSpecifierProvider>> results = new LinkedHashMap<String, List<FactorySettingSpecifierProvider>>(); synchronized (factories) { FactoryHelper helper = factories.get(factoryUID); if (helper != null) { for (Map.Entry<String, List<SettingSpecifierProvider>> me : helper.instanceEntrySet()) { String instanceUID = me.getKey(); List<FactorySettingSpecifierProvider> list = new ArrayList<FactorySettingSpecifierProvider>( me.getValue().size()); for (SettingSpecifierProvider provider : me.getValue()) { list.add(new BasicFactorySettingSpecifierProvider(instanceUID, provider)); } results.put(instanceUID, list); } } } return results; } @Override public Object getSettingValue(SettingSpecifierProvider provider, SettingSpecifier setting) { if (setting instanceof KeyedSettingSpecifier<?>) { KeyedSettingSpecifier<?> keyedSetting = (KeyedSettingSpecifier<?>) setting; if (keyedSetting.isTransient()) { return keyedSetting.getDefaultValue(); } final String providerUID = provider.getSettingUID(); final String instanceUID = (provider instanceof FactorySettingSpecifierProvider ? ((FactorySettingSpecifierProvider) provider).getFactoryInstanceUID() : null); try { Configuration conf = getConfiguration(providerUID, instanceUID); @SuppressWarnings("unchecked") Dictionary<String, ?> props = conf.getProperties(); Object val = (props == null ? null : props.get(keyedSetting.getKey())); if (val == null) { val = keyedSetting.getDefaultValue(); } return val; } catch (IOException e) { throw new RuntimeException(e); } catch (InvalidSyntaxException e) { throw new RuntimeException(e); } } return null; } @SuppressWarnings("unchecked") @Override public void updateSettings(SettingsCommand command) { // group all updates by provider+instance, to reduce the number of CA updates // when multiple settings are changed if (command.getProviderKey() == null) { Map<String, SettingsCommand> groups = new LinkedHashMap<String, SettingsCommand>(); for (SettingValueBean bean : command.getValues()) { String groupKey = bean.getProviderKey() + (bean.getInstanceKey() == null ? "" : bean.getInstanceKey()); SettingsCommand cmd = groups.get(groupKey); if (cmd == null) { cmd = new SettingsCommand(); cmd.setProviderKey(bean.getProviderKey()); cmd.setInstanceKey(bean.getInstanceKey()); groups.put(groupKey, cmd); } cmd.getValues().add(bean); } for (SettingsCommand cmd : groups.values()) { updateSettings(cmd); } return; } try { Configuration conf = getConfiguration(command.getProviderKey(), command.getInstanceKey()); Dictionary<String, Object> props = conf.getProperties(); if (props == null) { props = new Hashtable<String, Object>(); } for (SettingValueBean bean : command.getValues()) { String settingKey = command.getProviderKey(); String instanceKey = command.getInstanceKey(); if (instanceKey != null) { settingKey = getFactoryInstanceSettingKey(settingKey, instanceKey); } props.put(bean.getKey(), bean.getValue()); if (!bean.isTransient()) { settingDao.storeSetting(settingKey, bean.getKey(), bean.getValue()); } } if (conf != null && props != null) { if (command.getInstanceKey() != null) { props.put(OSGI_PROPERTY_KEY_FACTORY_INSTANCE_KEY, command.getInstanceKey()); } conf.update(props); } } catch (IOException e) { throw new RuntimeException(e); } catch (InvalidSyntaxException e) { throw new RuntimeException(e); } } @Override public String addProviderFactoryInstance(String factoryUID) { synchronized (factories) { List<KeyValuePair> instanceKeys = settingDao.getSettings(getFactorySettingKey(factoryUID)); int next = instanceKeys.size() + 1; // verify key doesn't exist boolean done = false; while (!done) { done = true; for (KeyValuePair instanceKey : instanceKeys) { if (instanceKey.getKey().equals(String.valueOf(next))) { done = false; next++; } } } String newInstanceKey = String.valueOf(next); settingDao.storeSetting(getFactorySettingKey(factoryUID), newInstanceKey, newInstanceKey); try { Configuration conf = getConfiguration(factoryUID, newInstanceKey); @SuppressWarnings("unchecked") Dictionary<String, Object> props = conf.getProperties(); if (props == null) { props = new Hashtable<String, Object>(); } props.put(OSGI_PROPERTY_KEY_FACTORY_INSTANCE_KEY, newInstanceKey); conf.update(props); return newInstanceKey; } catch (IOException e) { throw new RuntimeException(e); } catch (InvalidSyntaxException e) { throw new RuntimeException(e); } } } @Override public void deleteProviderFactoryInstance(String factoryUID, String instanceUID) { synchronized (factories) { // delete factory reference settingDao.deleteSetting(getFactorySettingKey(factoryUID), instanceUID); // delete instance values settingDao.deleteSetting(getFactoryInstanceSettingKey(factoryUID, instanceUID)); // delete Configuration try { Configuration conf = getConfiguration(factoryUID, instanceUID); conf.delete(); } catch (IOException e) { throw new RuntimeException(e); } catch (InvalidSyntaxException e) { throw new RuntimeException(e); } } } private static final String[] CSV_HEADERS = new String[] { "key", "type", "value", "flags", "modified" }; private static final String SETTING_MODIFIED_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; @Override public void exportSettingsCSV(Writer out) throws IOException { final ICsvBeanWriter writer = new CsvBeanWriter(out, CsvPreference.STANDARD_PREFERENCE); final List<IOException> errors = new ArrayList<IOException>(1); final CellProcessor[] processors = new CellProcessor[] { new org.supercsv.cellprocessor.Optional(), new org.supercsv.cellprocessor.Optional(), new org.supercsv.cellprocessor.Optional(), new CellProcessor() { @Override public Object execute(Object value, CsvContext ctx) { @SuppressWarnings("unchecked") Set<net.solarnetwork.node.Setting.SettingFlag> set = (Set<net.solarnetwork.node.Setting.SettingFlag>) value; if (set != null) { return net.solarnetwork.node.Setting.SettingFlag.maskForSet(set); } return 0; } }, new org.supercsv.cellprocessor.FmtDate(SETTING_MODIFIED_DATE_FORMAT) }; try { writer.writeHeader(CSV_HEADERS); settingDao.batchProcess(new BatchCallback<Setting>() { @Override public BatchCallbackResult handle(Setting domainObject) { try { writer.write(domainObject, CSV_HEADERS, processors); } catch (IOException e) { errors.add(e); return BatchCallbackResult.STOP; } return BatchCallbackResult.CONTINUE; } }, new BasicBatchOptions("Export Settings")); if (errors.size() > 0) { throw errors.get(0); } } finally { if (writer != null) { try { writer.flush(); writer.close(); } catch (IOException e) { // ignore these } } } } /** * A callback API for allowing the settings import process to decide which * settings should be imported. */ private interface ImportCallback { /** * Test if a specific should be imported at all. * * @param key * the setting key * @param type * the setting value * @param value * the setting value * @return <em>true</em> to allow the setting to be imported, * <em>false</em> to skip */ boolean shouldImportSetting(Setting setting); } @Override public void importSettingsCSV(Reader in) throws IOException { importSettingsCSV(in, new SettingsImportOptions()); } @Override public void importSettingsCSV(final Reader in, final SettingsImportOptions options) throws IOException { // TODO: need a better way to organize settings into "do not restore" category final Pattern allowed = Pattern.compile("^(?!solarnode).*", Pattern.CASE_INSENSITIVE); importSettingsCSV(in, new ImportCallback() { @Override public boolean shouldImportSetting(Setting s) { if (allowed.matcher(s.getKey()).matches() == false) { return false; } if (options.isAddOnly()) { // check if setting exists already, and if so do not import it if (settingDao.getSetting(s.getKey(), s.getType()) != null) { log.debug("Not updating existing setting {}", s.getKey()); return false; } } return true; } }); } private void importSettingsCSV(Reader in, final ImportCallback callback) throws IOException { final ICsvBeanReader reader = new CsvBeanReader(in, CsvPreference.STANDARD_PREFERENCE); final CellProcessor[] processors = new CellProcessor[] { null, new ConvertNullTo(""), null, new CellProcessor() { @Override public Object execute(Object arg, CsvContext ctx) { Set<net.solarnetwork.node.Setting.SettingFlag> set = null; if (arg != null) { int mask = Integer.parseInt(arg.toString()); set = net.solarnetwork.node.Setting.SettingFlag.setForMask(mask); } return set; } }, new org.supercsv.cellprocessor.ParseDate(SETTING_MODIFIED_DATE_FORMAT) }; reader.getHeader(true); transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(final TransactionStatus status) { Setting s; try { while ((s = reader.read(Setting.class, CSV_HEADERS, processors)) != null) { if (!callback.shouldImportSetting(s)) { continue; } if (s.getValue() == null) { settingDao.deleteSetting(s.getKey(), s.getType()); } else { settingDao.storeSetting(s); } } } catch (IOException e) { log.error("Unable to import settings: {}", e.getMessage()); status.setRollbackOnly(); } finally { try { reader.close(); } catch (IOException e) { // ingore } } } }); } @Override public SettingsBackup backupSettings() { final Date mrd = settingDao.getMostRecentModificationDate(); final SimpleDateFormat sdf = new SimpleDateFormat(BACKUP_DATE_FORMAT); final String lastBackupDateStr = settingDao.getSetting(SETTING_LAST_BACKUP_DATE); final Date lastBackupDate; try { lastBackupDate = (lastBackupDateStr == null ? null : sdf.parse(lastBackupDateStr)); } catch (ParseException e) { throw new RuntimeException("Unable to parse backup last date: " + e.getMessage()); } if (mrd == null || (lastBackupDate != null && lastBackupDate.after(mrd))) { log.debug("Settings unchanged since last backup on {}", lastBackupDateStr); return null; } final Date backupDate = new Date(); final String backupDateKey = sdf.format(backupDate); final File dir = new File(backupDestinationPath); if (!dir.exists()) { dir.mkdirs(); } final File f = new File(dir, BACKUP_FILENAME_PREFIX + backupDateKey + '.' + BACKUP_FILENAME_EXT); log.info("Backing up settings to {}", f.getPath()); Writer writer = null; try { writer = new BufferedWriter(new FileWriter(f)); exportSettingsCSV(writer); settingDao.storeSetting(new Setting(SETTING_LAST_BACKUP_DATE, null, backupDateKey, EnumSet.of(SettingFlag.IgnoreModificationDate))); } catch (IOException e) { log.error("Unable to create settings backup {}: {}", f.getPath(), e.getMessage()); } finally { try { writer.flush(); writer.close(); } catch (IOException e) { // ignore } } // clean out older backups File[] files = dir.listFiles(new RegexFileFilter(BACKUP_FILENAME_PATTERN)); if (files != null && files.length > backupMaxCount) { // sort array Arrays.sort(files, new FilenameReverseComparator()); for (int i = backupMaxCount; i < files.length; i++) { if (!files[i].delete()) { log.warn("Unable to delete old settings backup file {}", files[i]); } } } return new SettingsBackup(backupDateKey, backupDate); } @Override public Collection<SettingsBackup> getAvailableBackups() { final File dir = new File(backupDestinationPath); File[] files = dir.listFiles(new RegexFileFilter(BACKUP_FILENAME_PATTERN)); if (files == null || files.length == 0) { return Collections.emptyList(); } Arrays.sort(files, new FilenameReverseComparator()); List<SettingsBackup> list = new ArrayList<SettingsBackup>(files.length); SimpleDateFormat sdf = new SimpleDateFormat(BACKUP_DATE_FORMAT); for (File f : files) { Matcher m = BACKUP_FILENAME_PATTERN.matcher(f.getName()); if (m.matches()) { String dateStr = m.group(1); try { list.add(new SettingsBackup(dateStr, sdf.parse(dateStr))); } catch (ParseException e) { log.warn("Unable to parse backup file date from filename {}: {}", f.getName(), e.getMessage()); } } } return list; } @Override public Reader getReaderForBackup(SettingsBackup backup) { final File dir = new File(backupDestinationPath); try { final String fname = BACKUP_FILENAME_PREFIX + backup.getBackupKey() + '.' + BACKUP_FILENAME_EXT; final File f = new File(dir, fname); if (f.canRead()) { return new BufferedReader(new FileReader(f)); } } catch (FileNotFoundException e) { return null; } return null; } @Override public String getKey() { return CASettingsService.class.getName(); } private static final String BACKUP_RESOURCE_SETTINGS_CSV = "settings.csv"; @Override public Iterable<BackupResource> getBackupResources() { // create resource from our settings CSV data ByteArrayOutputStream byos = new ByteArrayOutputStream(); try { OutputStreamWriter writer = new OutputStreamWriter(byos, "UTF-8"); exportSettingsCSV(writer); } catch (IOException e) { log.error("Unable to create settings backup resource", e); } List<BackupResource> resources = new ArrayList<BackupResource>(1); resources.add(new ResourceBackupResource(new ByteArrayResource(byos.toByteArray()), BACKUP_RESOURCE_SETTINGS_CSV)); return resources; } @Override public boolean restoreBackupResource(BackupResource resource) { if (BACKUP_RESOURCE_SETTINGS_CSV.equalsIgnoreCase(resource.getBackupPath())) { try { // TODO: need a better way to organize settings into "do not restore" category final Pattern notAllowed = Pattern.compile("^solarnode.*", Pattern.CASE_INSENSITIVE); InputStreamReader reader = new InputStreamReader(resource.getInputStream(), "UTF-8"); importSettingsCSV(reader, new ImportCallback() { @Override public boolean shouldImportSetting(Setting s) { if (notAllowed.matcher(s.getKey()).matches()) { // only allow restoring solarnode keys if their type is NOT empty return (s.getType() != null && s.getType().length() > 0); } return true; } }); return true; } catch (IOException e) { log.error("Unable to restore settings backup resource", e); } } return false; } private static class FilenameReverseComparator implements Comparator<File> { @Override public int compare(File o1, File o2) { // order in reverse, and then we can delete all but maxBackupCount return o2.getName().compareTo(o1.getName()); } } private static class RegexFileFilter implements FileFilter { final Pattern p; private RegexFileFilter(Pattern p) { super(); this.p = p; } @Override public boolean accept(File pathname) { Matcher m = p.matcher(pathname.getName()); return m.matches(); } } private Configuration getConfiguration(String providerUID, String factoryInstanceUID) throws IOException, InvalidSyntaxException { Configuration conf = null; if (factoryInstanceUID == null) { conf = configurationAdmin.getConfiguration(providerUID, null); } else { conf = findExistingConfiguration(providerUID, factoryInstanceUID); if (conf == null) { conf = configurationAdmin.createFactoryConfiguration(providerUID, null); } } return conf; } private Configuration findExistingConfiguration(String pid, String instanceKey) throws IOException, InvalidSyntaxException { String filter = "(&(" + ConfigurationAdmin.SERVICE_FACTORYPID + "=" + pid + ")(" + OSGI_PROPERTY_KEY_FACTORY_INSTANCE_KEY + "=" + instanceKey + "))"; Configuration[] configurations = configurationAdmin.listConfigurations(filter); if (configurations != null && configurations.length > 0) { return configurations[0]; } else { return null; } } public void setConfigurationAdmin(ConfigurationAdmin configurationAdmin) { this.configurationAdmin = configurationAdmin; } public void setSettingDao(SettingDao settingDao) { this.settingDao = settingDao; } public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; } public void setBackupDestinationPath(String backupDestinationPath) { this.backupDestinationPath = backupDestinationPath; } public void setBackupMaxCount(int backupMaxCount) { this.backupMaxCount = backupMaxCount; } }