/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.sling.installer.factories.configuration.impl; import java.io.IOException; import java.lang.reflect.Array; import java.util.Dictionary; import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; import java.util.Set; import org.osgi.framework.Constants; import org.osgi.framework.InvalidSyntaxException; import org.osgi.service.cm.Configuration; import org.osgi.service.cm.ConfigurationAdmin; /** * Utilities for configuration handling */ abstract class ConfigUtil { /** * This property marks the configuration as being deleted. */ public static final String PROPERTY_DELETE_MARKER = "org.apache.sling.installer.configuration.deleted"; /** * This property has been used in older versions to keep track where the * configuration has been installed from. */ private static final String CONFIG_PATH_KEY = "org.apache.sling.installer.osgi.path"; /** * This property has been used in older versions to keep track of factory * configurations. */ private static final String ALIAS_KEY = "org.apache.sling.installer.osgi.factoryaliaspid"; /** Configuration properties to ignore when comparing configs */ private static final Set<String> IGNORED_PROPERTIES = new HashSet<String>(); static { IGNORED_PROPERTIES.add(Constants.SERVICE_PID); IGNORED_PROPERTIES.add(CONFIG_PATH_KEY); IGNORED_PROPERTIES.add(ALIAS_KEY); IGNORED_PROPERTIES.add(ConfigurationAdmin.SERVICE_FACTORYPID); } private static Set<String> collectKeys(final Dictionary<String, Object>a) { final Set<String> keys = new HashSet<String>(); final Enumeration<String> aI = a.keys(); while (aI.hasMoreElements() ) { final String key = aI.nextElement(); if ( !IGNORED_PROPERTIES.contains(key) ) { keys.add(key); } } return keys; } /** * Convert the object to an array * @param value The array * @return an object array */ private static Object[] convertToObjectArray(final Object value) { final Object[] values = new Object[Array.getLength(value)]; for(int i=0;i<values.length;i++) { values[i] = Array.get(value, i); } return values; } /** True if a and b represent the same config data, ignoring "non-configuration" keys in the dictionaries */ public static boolean isSameData(Dictionary<String, Object>a, Dictionary<String, Object>b) { boolean result = false; if (a != null && b != null) { final Set<String> keysA = collectKeys(a); final Set<String> keysB = collectKeys(b); if ( keysA.size() == keysB.size() && keysA.containsAll(keysB) ) { result = true; for(final String key : keysA ) { final Object valA = a.get(key); final Object valB = b.get(key); if ( valA.getClass().isArray() ) { final Object[] arrA = convertToObjectArray(valA); final Object[] arrB = convertToObjectArray(valB); if ( arrA.length != arrB.length ) { result = false; break; } for(int i=0; i<arrA.length; i++) { if ( !(String.valueOf(arrA[i]).equals(String.valueOf(arrB[i]))) ) { result = false; break; } } } else { // we always do a string comparison if ( !(String.valueOf(valA).equals(String.valueOf(valB))) ) { result = false; break; } } } } } return result; } /** * Remove all ignored properties */ public static Dictionary<String, Object> cleanConfiguration(final Dictionary<String, Object> config) { final Dictionary<String, Object> cleanedConfig = new Hashtable<String, Object>(); final Enumeration<String> e = config.keys(); while(e.hasMoreElements()) { final String key = e.nextElement(); if ( !IGNORED_PROPERTIES.contains(key) ) { cleanedConfig.put(key, config.get(key)); } } return cleanedConfig; } /** * Encode the value for the ldap filter: \, *, (, and ) should be escaped. */ private static String encode(final String value) { return value.replace("\\", "\\\\") .replace("*", "\\*") .replace("(", "\\(") .replace(")", "\\)"); } public static Configuration getConfiguration(final ConfigurationAdmin ca, final String factoryPid, final String configPid) throws IOException, InvalidSyntaxException { return getOrCreateConfiguration(ca, factoryPid, configPid, null, false); } public static Configuration createConfiguration(final ConfigurationAdmin ca, final String factoryPid, final String configPid, final String location) throws IOException, InvalidSyntaxException { return getOrCreateConfiguration(ca, factoryPid, configPid, location, true); } private static Configuration getOrCreateConfiguration(final ConfigurationAdmin ca, final String factoryPid, final String configPid, final String location, final boolean createIfNeeded) throws IOException, InvalidSyntaxException { Configuration result = null; if (factoryPid == null) { if (createIfNeeded) { result = ca.getConfiguration(configPid, location); } else { String filter = "(" + Constants.SERVICE_PID + "=" + encode(configPid) + ")"; Configuration[] configs = ca.listConfigurations(filter); if (configs != null && configs.length > 0) { result = configs[0]; } } } else { Configuration configs[] = null; if ( configPid != null ) { configs = ca.listConfigurations("(&(" + ConfigurationAdmin.SERVICE_FACTORYPID + "=" + encode(factoryPid) + ")(" + Constants.SERVICE_PID + "=" + encode(configPid) + "))"); } if (configs == null || configs.length == 0) { // check for old style with alias pid configs = ca.listConfigurations( "(&(" + ConfigurationAdmin.SERVICE_FACTORYPID + "=" + factoryPid + ")(" + ALIAS_KEY + "=" + encode(configPid) + "))"); if (configs == null || configs.length == 0) { if (createIfNeeded) { result = ca.createFactoryConfiguration(factoryPid, location); } } else { result = configs[0]; } } else { result = configs[0]; } } return result; } public static boolean toBoolean(final Object obj, final boolean defaultValue) { boolean result = defaultValue; if ( obj != null ) { if (obj instanceof Boolean) { result = ((Boolean) obj).booleanValue(); } else { result = Boolean.valueOf(String.valueOf(obj)); } } return result; } }