blob: ebab0e155809099bcb5e3fb89fd860cb4cb80638 [file] [log] [blame]
/*
* Licensed 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.karaf.cellar.config;
import org.apache.karaf.cellar.core.CellarSupport;
import org.apache.karaf.cellar.core.Configurations;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import java.io.*;
import java.net.URI;
import java.net.URL;
import java.util.*;
/**
* Generic configuration support.
*/
public class ConfigurationSupport extends CellarSupport {
private static final String FELIX_FILEINSTALL_FILENAME = "felix.fileinstall.filename";
private static final String KARAF_CELLAR_FILENAME = "karaf.cellar.filename";
private static final String KARAF_CELLAR_CONTENT = "karaf.cellar.content";
private static final String KARAF_CELLAR_REMOVED = "karaf.cellar.removed";
protected File storage;
/**
* Read a {@code Dictionary} and create a corresponding {@code Properties}.
*
* @param dictionary the source dictionary.
* @return the corresponding properties.
*/
public Properties dictionaryToProperties(Dictionary dictionary) {
Properties properties = new Properties();
if (dictionary != null) {
Enumeration keys = dictionary.keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (key != null && dictionary.get(key) != null) {
properties.put(key, dictionary.get(key));
}
}
}
return properties;
}
/**
* Returns true if dictionaries are equal.
*
* @param source the source dictionary.
* @param target the target dictionary.
* @return true if the two dictionaries are equal, false else.
*/
protected boolean equals(Dictionary source, Dictionary target) {
if (source == null && target == null)
return true;
if (source == null || target == null)
return false;
if (source.isEmpty() && target.isEmpty())
return true;
if (source.size() != target.size())
return false;
Enumeration sourceKeys = source.keys();
while (sourceKeys.hasMoreElements()) {
Object key = sourceKeys.nextElement();
if (!key.equals(org.osgi.framework.Constants.SERVICE_PID)) {
Object sourceValue = source.get(key);
Object targetValue = target.get(key);
if (sourceValue != null && targetValue == null)
return false;
if (sourceValue == null && targetValue != null)
return false;
if (!sourceValue.equals(targetValue))
return false;
}
}
return true;
}
public boolean canDistributeConfig(Dictionary dictionary) {
if (dictionary.get(ConfigurationAdmin.SERVICE_FACTORYPID) != null) {
return dictionary.get(KARAF_CELLAR_FILENAME) != null;
}
return true;
}
public boolean shouldReplicateConfig(Dictionary clusterDictionary) {
return clusterDictionary.get(KARAF_CELLAR_REMOVED) == null;
}
/**
* Filter a dictionary, and populate a target dictionary.
*
* @param dictionary the source dictionary.
* @return the filtered dictionary
*/
public Dictionary filter(Dictionary dictionary) {
Dictionary result = new Properties();
if (dictionary != null) {
Enumeration sourceKeys = dictionary.keys();
while (sourceKeys.hasMoreElements()) {
String key = (String) sourceKeys.nextElement();
if (key.equals(FELIX_FILEINSTALL_FILENAME)) {
String value = dictionary.get(key).toString();
value = value.substring(value.lastIndexOf("/") + 1);
result.put(KARAF_CELLAR_FILENAME, value);
try {
result.put(KARAF_CELLAR_CONTENT, readFile(new File(storage, value)));
} catch (IOException e) {
// Cannot read file
}
} else if (!isExcludedProperty(key)) {
Object value = dictionary.get(key);
result.put(key, value);
}
}
}
return result;
}
public Properties getDeletedConfigurationMarker(Dictionary dictionary) {
Properties result = new Properties();
result.put(org.osgi.framework.Constants.SERVICE_PID, dictionary.get(org.osgi.framework.Constants.SERVICE_PID));
result.put(KARAF_CELLAR_FILENAME, dictionary.get(KARAF_CELLAR_FILENAME));
result.put(KARAF_CELLAR_REMOVED, true);
return result;
}
public Configuration findLocalConfiguration(String pid, Dictionary dictionary) throws IOException, InvalidSyntaxException {
String filter;
Object filename = dictionary != null ? dictionary.get(KARAF_CELLAR_FILENAME) : null;
if (filename != null) {
String uri = new File(storage, filename.toString()).toURI().toString();
filter = "(|(" + FELIX_FILEINSTALL_FILENAME + "=" + uri + ")(" + KARAF_CELLAR_FILENAME + "=" + dictionary.get(KARAF_CELLAR_FILENAME) + ")(" + org.osgi.framework.Constants.SERVICE_PID + "=" + pid + "))";
} else {
filter = "(" + org.osgi.framework.Constants.SERVICE_PID + "=" + pid + ")";
}
Configuration[] localConfigurations = configurationAdmin.listConfigurations(filter);
return (localConfigurations != null && localConfigurations.length > 0) ? localConfigurations[0] : null;
}
public Configuration createLocalConfiguration(String pid, Dictionary clusterDictionary) throws IOException {
Configuration localConfiguration;
Object factoryPid = clusterDictionary.get(ConfigurationAdmin.SERVICE_FACTORYPID);
if (factoryPid != null) {
localConfiguration = configurationAdmin.createFactoryConfiguration(factoryPid.toString(), null);
} else {
localConfiguration = configurationAdmin.getConfiguration(pid, null);
}
return localConfiguration;
}
public Dictionary convertPropertiesFromCluster(Dictionary dictionary) {
Dictionary result = new Properties();
if (dictionary != null) {
Enumeration sourceKeys = dictionary.keys();
while (sourceKeys.hasMoreElements()) {
String key = (String) sourceKeys.nextElement();
if (key.equals(KARAF_CELLAR_FILENAME)) {
String value = dictionary.get(key).toString();
result.put(FELIX_FILEINSTALL_FILENAME, new File(storage, value).toURI().toString());
} else if (key.equals(KARAF_CELLAR_CONTENT)) {
// skip
} else {
Object value = dictionary.get(key);
result.put(key, value);
}
}
}
return result;
}
/**
* Check if a property is in the default excluded list.
*
* @param propertyName the property name to check.
* @return true is the property is excluded, false else.
*/
public boolean isExcludedProperty(String propertyName) {
try {
Configuration nodeConfiguration = configurationAdmin.getConfiguration(Configurations.NODE, null);
if (nodeConfiguration != null) {
Dictionary properties = nodeConfiguration.getProperties();
if (properties != null) {
String property = properties.get("config.excluded.properties").toString();
String[] excludedProperties = property.split(",");
for (int i = 0; i < excludedProperties.length; i++) {
if (excludedProperties[i].trim().equals(propertyName))
return true;
}
}
}
} catch (Exception e) {
LOGGER.warn("CELLAR CONFIG: can't check excluded properties", e);
}
return false;
}
/**
* Persist a configuration to a storage.
* @param cfg the configuration to store.
*/
protected void persistConfiguration(Configuration cfg, Dictionary clusterDictionary) {
try {
File storageFile = getStorageFile(cfg.getProperties());
if (storageFile == null && cfg.getProperties().get(ConfigurationAdmin.SERVICE_FACTORYPID) != null) {
storageFile = new File(storage, cfg.getPid() + ".cfg");
}
if (storageFile == null) {
// it's a factory configuration without filename specified, cannot save
return;
}
String content = clusterDictionary == null ? null : (String) clusterDictionary.get(KARAF_CELLAR_CONTENT);
if (content == null) {
org.apache.felix.utils.properties.Properties p = new org.apache.felix.utils.properties.Properties(storageFile);
List<String> propertiesToRemove = new ArrayList<String>();
Set<String> set = p.keySet();
for (String key : set) {
if (!org.osgi.framework.Constants.SERVICE_PID.equals(key)
&& !ConfigurationAdmin.SERVICE_FACTORYPID.equals(key)
&& !KARAF_CELLAR_FILENAME.equals(key)
&& !FELIX_FILEINSTALL_FILENAME.equals(key)) {
propertiesToRemove.add(key);
}
}
for (String key : propertiesToRemove) {
p.remove(key);
}
Dictionary props = cfg.getProperties();
for (Enumeration<String> keys = props.keys(); keys.hasMoreElements(); ) {
String key = keys.nextElement();
if (!org.osgi.framework.Constants.SERVICE_PID.equals(key)
&& !ConfigurationAdmin.SERVICE_FACTORYPID.equals(key)
&& !KARAF_CELLAR_FILENAME.equals(key)
&& !FELIX_FILEINSTALL_FILENAME.equals(key)) {
p.put(key, (String) props.get(key));
}
}
// save the cfg file
storage.mkdirs();
p.save();
} else {
writeFile(storageFile, content);
}
} catch (Exception e) {
LOGGER.error("CELLAR CONFIG: Issue when trying to persist configuration file", e);
}
}
private File getStorageFile(Dictionary properties) throws IOException {
File storageFile = null;
Object val = properties.get(FELIX_FILEINSTALL_FILENAME);
try {
if (val instanceof URL) {
storageFile = new File(((URL) val).toURI());
}
if (val instanceof URI) {
storageFile = new File((URI) val);
}
if (val instanceof String) {
storageFile = new File(new URL((String) val).toURI());
}
} catch (Exception e) {
throw new IOException(e.getMessage(), e);
}
return storageFile;
}
public String getKarafFilename(Dictionary dictionary) {
return (String) filter(dictionary).get(KARAF_CELLAR_FILENAME);
}
/**
* Delete the configuration.
*
* @param localConfiguration the configuration PID to delete.
*/
protected void deleteConfiguration(Configuration localConfiguration) throws IOException {
String filename = getKarafFilename(localConfiguration.getProperties());
localConfiguration.delete();
File cfgFile = new File(storage, filename == null ? (localConfiguration.getPid() + ".cfg") : filename);
if (cfgFile.exists()) {
cfgFile.delete();
}
}
public File getStorage() {
return storage;
}
public void setStorage(File storage) {
this.storage = storage;
}
private String readFile(File file) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(file));
try {
String line = reader.readLine();
StringBuilder sb = new StringBuilder();
while(line != null){
sb.append(line).append("\n");
line = reader.readLine();
}
return sb.toString();
} finally {
reader.close();
}
}
private void writeFile(File file, String content) throws IOException {
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
try {
writer.write(content);
} finally {
writer.close();
}
}
}