aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java
diff options
context:
space:
mode:
authorLyubomir Marinov <lyubomir.marinov@jitsi.org>2009-08-04 16:34:22 +0000
committerLyubomir Marinov <lyubomir.marinov@jitsi.org>2009-08-04 16:34:22 +0000
commit19f509b6524fea5b253e1166841c7e0947b06573 (patch)
treed01c8de25454dfbea7f0d6ee71acc466fd6102ff /src/net/java
parente1d01dd9a0858ea5b53b1d17a1a0451b4d25fda7 (diff)
downloadjitsi-19f509b6524fea5b253e1166841c7e0947b06573.zip
jitsi-19f509b6524fea5b253e1166841c7e0947b06573.tar.gz
jitsi-19f509b6524fea5b253e1166841c7e0947b06573.tar.bz2
- Provides an alternative storage backend to XML in the ConfigurationService implementation which uses Properties for the sake for better execution speed and garbage collection behavior.
- Implements batch configuration property modifications which allow a caller to modify a set of properties with a single saving of the configuration file.
Diffstat (limited to 'src/net/java')
-rw-r--r--src/net/java/sip/communicator/impl/configuration/ConfigurationActivator.java37
-rw-r--r--src/net/java/sip/communicator/impl/configuration/ConfigurationServiceImpl.java802
-rw-r--r--src/net/java/sip/communicator/impl/notification/NotificationServiceImpl.java34
-rw-r--r--src/net/java/sip/communicator/impl/protocol/AccountManagerImpl.java14
-rw-r--r--src/net/java/sip/communicator/service/configuration/ConfigurationService.java3
-rw-r--r--src/net/java/sip/communicator/service/configuration/PropertyVetoException.java9
6 files changed, 332 insertions, 567 deletions
diff --git a/src/net/java/sip/communicator/impl/configuration/ConfigurationActivator.java b/src/net/java/sip/communicator/impl/configuration/ConfigurationActivator.java
index b2db315..02584a2 100644
--- a/src/net/java/sip/communicator/impl/configuration/ConfigurationActivator.java
+++ b/src/net/java/sip/communicator/impl/configuration/ConfigurationActivator.java
@@ -13,31 +13,31 @@ import net.java.sip.communicator.util.*;
/**
* @author Emil Ivov
+ * @author Lubomir Marinov
*/
public class ConfigurationActivator
implements BundleActivator
{
- /**
- * The current bundle context
- */
- public static BundleContext bundleContext;
-
- private final Logger logger = Logger.getLogger(ConfigurationServiceImpl.class);
- private ConfigurationServiceImpl impl = new ConfigurationServiceImpl();
+ private final Logger logger
+ = Logger.getLogger(ConfigurationServiceImpl.class);
+
+ private final ConfigurationServiceImpl impl
+ = new ConfigurationServiceImpl();
/**
* Starts the configuration service
- *
- * @param bundleContext the BundleContext as provided from the osgi
- * framework.
- * @throws Exception if anything goes wrong
+ *
+ * @param bundleContext
+ * the BundleContext as provided from the OSGi framework.
+ * @throws Exception
+ * if anything goes wrong
*/
- public void start(BundleContext bContext) throws Exception
+ public void start(BundleContext bundleContext)
+ throws Exception
{
logger.debug("Service Impl: " + getClass().getName() + " [ STARTED ]");
-
- ConfigurationActivator.bundleContext = bContext;
- impl.start();
+
+ impl.start(bundleContext);
bundleContext.registerService(ConfigurationService.class.getName(),
impl,
@@ -48,12 +48,13 @@ public class ConfigurationActivator
/**
* Causes the configuration service to store the properties object and
- * unregisters the configuration servcice.
+ * unregisters the configuration service.
*
- * @param bundlecontext BundleContext
+ * @param bundleContext BundleContext
* @throws Exception
*/
- public void stop(BundleContext bundlecontext) throws Exception
+ public void stop(BundleContext bundleContext)
+ throws Exception
{
logger.logEntry();
impl.stop();
diff --git a/src/net/java/sip/communicator/impl/configuration/ConfigurationServiceImpl.java b/src/net/java/sip/communicator/impl/configuration/ConfigurationServiceImpl.java
index e9d4431..1c9c67d 100644
--- a/src/net/java/sip/communicator/impl/configuration/ConfigurationServiceImpl.java
+++ b/src/net/java/sip/communicator/impl/configuration/ConfigurationServiceImpl.java
@@ -9,8 +9,6 @@ package net.java.sip.communicator.impl.configuration;
import java.io.*;
import java.util.*;
-import javax.xml.parsers.*;
-
import net.java.sip.communicator.impl.configuration.xml.*;
import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.service.configuration.event.*;
@@ -19,8 +17,6 @@ import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.xml.*;
import org.osgi.framework.*;
-import org.w3c.dom.*;
-import org.xml.sax.*;
/**
* A straight forward implementation of the ConfigurationService using an xml
@@ -38,23 +34,6 @@ public class ConfigurationServiceImpl
private final Logger logger = Logger.getLogger(ConfigurationServiceImpl.class);
/**
- * The XML Document containing the configuration file this service loaded.
- */
- private Document propertiesDocument = null;
-
- /** Name of the xml attribute containing property values */
- private static final String ATTRIBUTE_VALUE = "value";
-
- /**
- * Name of the xml attribute indicating that a property is to be resolved
- * in the system properties
- */
- private static final String SYSTEM_ATTRIBUTE_NAME = "system";
-
- /** The value of the Name of the xml attribute containing property values */
- private static final String SYSTEM_ATTRIBUTE_TRUE = "true";
-
- /**
* The name of the system property that stores the name of the configuration
* file.
*/
@@ -76,21 +55,6 @@ public class ConfigurationServiceImpl
new ChangeEventDispatcher(this);
/**
- * The list of properties currently registered in the configuration service.
- */
- private Map<String, Object> properties = new Hashtable<String, Object>();
-
- /**
- * Contains the properties that were initially loaded from the configuration
- * file or (if the properties have been modified and saved since initially
- * loaded) those that were last written to the file.We use the property so
- * that we could determine which properties are new and do not have a
- * corresponding node in the XMLDocument object.
- */
- private Map<String, Object> fileExtractedProperties =
- new Hashtable<String, Object>();
-
- /**
* Indicates whether the service is started or stopped.
*/
private boolean started = false;
@@ -100,6 +64,8 @@ public class ConfigurationServiceImpl
*/
private FileAccessService faService = null;
+ private ConfigurationStore store;
+
/**
* Sets the property with the specified name to the specified value. Calling
* this method would first trigger a PropertyChangeEvent that will
@@ -132,7 +98,7 @@ public class ConfigurationServiceImpl
* @param isSystem specifies whether or not the property being is a System
* property and should be resolved against the system
* property set. If the property has previously been
- * specified as system then this value is inteernally forced
+ * specified as system then this value is internally forced
* to true.
* @throws PropertyVetoException in case the changed has been refused by
* at least one propertychange listener.
@@ -142,6 +108,7 @@ public class ConfigurationServiceImpl
throws PropertyVetoException
{
Object oldValue = getProperty(propertyName);
+
//first check whether the change is ok with everyone
if (changeEventDispatcher.hasVetoableChangeListeners(propertyName))
changeEventDispatcher.fireVetoableChange(
@@ -153,7 +120,74 @@ public class ConfigurationServiceImpl
logger.trace(propertyName + "( oldValue=" + oldValue
+ ", newValue=" + property + ".");
- //once set system, a property remains system event if the user
+ doSetProperty(propertyName, property, isSystem);
+
+ try
+ {
+ storeConfiguration();
+ }
+ catch (IOException ex)
+ {
+ logger.error(
+ "Failed to store configuration after a property change");
+ }
+
+ if (changeEventDispatcher.hasPropertyChangeListeners(propertyName))
+ changeEventDispatcher.firePropertyChange(
+ propertyName, oldValue, property);
+ }
+
+ public void setProperties(Map<String, Object> properties)
+ throws PropertyVetoException
+ {
+ //first check whether the changes are ok with everyone
+ Map<String, Object> oldValues
+ = new HashMap<String, Object>(properties.size());
+ for (Map.Entry<String, Object> property : properties.entrySet())
+ {
+ String propertyName = property.getKey();
+ Object oldValue = getProperty(propertyName);
+
+ oldValues.put(propertyName, oldValue);
+
+ if (changeEventDispatcher.hasVetoableChangeListeners(propertyName))
+ changeEventDispatcher
+ .fireVetoableChange(
+ propertyName,
+ oldValue,
+ property.getValue());
+ }
+
+ for (Map.Entry<String, Object> property : properties.entrySet())
+ doSetProperty(property.getKey(), property.getValue(), false);
+
+ try
+ {
+ storeConfiguration();
+ }
+ catch (IOException ex)
+ {
+ logger.error(
+ "Failed to store configuration after property changes");
+ }
+
+ for (Map.Entry<String, Object> property : properties.entrySet())
+ {
+ String propertyName = property.getKey();
+
+ if (changeEventDispatcher.hasPropertyChangeListeners(propertyName))
+ changeEventDispatcher
+ .firePropertyChange(
+ propertyName,
+ oldValues.get(propertyName),
+ property.getValue());
+ }
+ }
+
+ private void doSetProperty(
+ String propertyName, Object property, boolean isSystem)
+ {
+ //once set system, a property remains system even if the user
//specified sth else
if (isSystem(propertyName))
@@ -161,9 +195,7 @@ public class ConfigurationServiceImpl
if (property == null)
{
- properties.remove(propertyName);
-
- fileExtractedProperties.remove(propertyName);
+ store.removeProperty(propertyName);
if (isSystem)
{
@@ -178,29 +210,15 @@ public class ConfigurationServiceImpl
//in case this is a system property, we must only store it
//in the System property set and keep only a ref locally.
System.setProperty(propertyName, property.toString());
- properties.put(propertyName,
- new PropertyReference(propertyName));
+ store.setSystemProperty(propertyName);
}
else
{
- properties.put(propertyName, property);
+ store.setNonSystemProperty(propertyName, property);
}
}
- if (changeEventDispatcher.hasPropertyChangeListeners(propertyName))
- changeEventDispatcher.firePropertyChange(
- propertyName, oldValue, property);
-
- try
- {
- storeConfiguration();
- }
- catch (IOException ex)
- {
- logger.error("Failed to store configuration after "
- + "a property change");
- }
}
-
+
/**
* Removes the property with the specified name. Calling
* this method would first trigger a PropertyChangeEvent that will
@@ -210,7 +228,6 @@ public class ConfigurationServiceImpl
* All properties with prefix propertyName will also be removed.
* <p>
* @param propertyName the name of the property to change.
- * @param property the new value of the specified property.
* @throws PropertyVetoException in case the changed has been refused by
* at least one propertychange listener.
*/
@@ -237,9 +254,7 @@ public class ConfigurationServiceImpl
logger.trace("Will remove prop: " + propertyName + ".");
- properties.remove(propertyName);
-
- fileExtractedProperties.remove(propertyName);
+ store.removeProperty(propertyName);
if (changeEventDispatcher.hasPropertyChangeListeners(propertyName))
changeEventDispatcher.firePropertyChange(
@@ -259,19 +274,13 @@ public class ConfigurationServiceImpl
/**
* Returns the value of the property with the specified name or null if no
* such property exists.
+ *
* @param propertyName the name of the property that is being queried.
* @return the value of the property with the specified name.
*/
public Object getProperty(String propertyName)
{
- Object value = properties.get(propertyName);
-
- //if this is a property reference make sure we return the referenced
- //value and not the reference itself
- if(value instanceof PropertyReference)
- return ((PropertyReference)value).getValue();
- else
- return value;
+ return store.getProperty(propertyName);
}
/**
@@ -308,7 +317,7 @@ public class ConfigurationServiceImpl
{
List<String> resultKeySet = new LinkedList<String>();
- for (String key : properties.keySet())
+ for (String key : store.getPropertyNames())
{
int ix = key.lastIndexOf('.');
@@ -438,13 +447,14 @@ public class ConfigurationServiceImpl
/**
* Initializes the configuration service impl and makes it load an initial
* configuration from the conf file.
+ *
+ * @param bc
*/
- void start()
+ void start(BundleContext bc)
{
this.started = true;
// retrieve a reference to the FileAccessService
- BundleContext bc = ConfigurationActivator.bundleContext;
ServiceReference faServiceReference = bc.getServiceReference(
FileAccessService.class.getName());
this.faService = (FileAccessService) bc.getService(faServiceReference);
@@ -468,27 +478,10 @@ public class ConfigurationServiceImpl
public void reloadConfiguration()
throws IOException, XMLException
{
- properties = new Hashtable<String, Object>();
this.configurationFile = null;
- fileExtractedProperties =
- loadConfiguration(getConfigurationFile());
- this.properties.putAll(fileExtractedProperties);
- }
+ File file = getConfigurationFile();
- /**
- * Loads the contents of the specified configuration file into the local
- * properties object.
- * @param file a reference to the configuration file to load.
- * @return a hashtable containing all properties extracted from the
- * specified file.
- *
- * @throws IOException if the specified file does not exist
- * @throws XMLException if there is a problem with the file syntax.
- */
- Map<String, Object> loadConfiguration(File file)
- throws IOException, XMLException
- {
// restore the file if needed
FailSafeTransaction trans = this.faService
.createFailSafeTransaction(file);
@@ -498,51 +491,8 @@ public class ConfigurationServiceImpl
logger.error("can't restore the configuration file before loading" +
" it", e);
}
-
- try
- {
- DocumentBuilderFactory factory =
- DocumentBuilderFactory.newInstance();
- DocumentBuilder builder = factory.newDocumentBuilder();
- Map<String, Object> props = new Hashtable<String, Object>();
-
- //if the file is empyt (or contains only sth insignificant)
- //ifnore it and create a new document.
- if(file.length() < "<sip-communicator>".length()*2)
- propertiesDocument = createPropertiesDocument();
- else
- propertiesDocument = builder.parse(file);
-
- Node root = propertiesDocument.getFirstChild();
-
- Node currentNode = null;
- NodeList children = root.getChildNodes();
- for(int i = 0; i < children.getLength(); i++)
- {
- currentNode = children.item(i);
-
- if(currentNode.getNodeType() == Node.ELEMENT_NODE)
- {
- StringBuffer propertyNameBuff = new StringBuffer();
- propertyNameBuff.append(currentNode.getNodeName());
- loadNode(currentNode, propertyNameBuff, props);
- }
- }
- return props;
- }
- catch(SAXException ex)
- {
- logger.error("Error parsing configuration file", ex);
- throw new XMLException(ex.getMessage(), ex);
- }
- catch(ParserConfigurationException ex)
- {
- //it is not highly probable that this might happen - so lets just
- //log it.
- logger.error("Error finding configuration for default parsers", ex);
- return new Hashtable<String, Object>();
- }
+ store.reloadConfiguration(file);
}
public synchronized void storeConfiguration()
@@ -551,229 +501,120 @@ public class ConfigurationServiceImpl
storeConfiguration(getConfigurationFile());
}
- private Document createPropertiesDocument()
- {
- if(propertiesDocument == null)
- {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- DocumentBuilder builder = null;
- try
- {
- builder = factory.newDocumentBuilder();
- }
- catch (ParserConfigurationException ex)
- {
- logger.error("Failed to create a DocumentBuilder", ex);
- return null;
- }
- propertiesDocument = builder.newDocument();
- propertiesDocument.appendChild(
- propertiesDocument.createElement("sip-communicator"));
- }
- return propertiesDocument;
- }
-
/**
* Stores local properties in the specified configuration file.
+ *
* @param file a reference to the configuration file where properties should
- * be stored.
+ * be stored.
* @throws IOException if there was a problem writing to the specified file.
*/
private void storeConfiguration(File file)
throws IOException
{
- if(!started)
- throw new IllegalStateException("Service is stopped or has not been started");
-
- //resolve the properties that were initially in the file - back to
- //the document.
-
- if (propertiesDocument == null)
- propertiesDocument = createPropertiesDocument();
-
- Node root = propertiesDocument.getFirstChild();
-
- Node currentNode = null;
- NodeList children = root.getChildNodes();
- for (int i = 0; i < children.getLength(); i++)
- {
- currentNode = children.item(i);
+ if (!started)
+ throw new IllegalStateException(
+ "Service is stopped or has not been started");
- if (currentNode.getNodeType() == Node.ELEMENT_NODE)
- {
- StringBuffer propertyNameBuff = new StringBuffer();
- propertyNameBuff.append(currentNode.getNodeName());
- updateNode(currentNode, propertyNameBuff, properties);
- }
- }
-
- //create in the document the properties that were added by other
- //bundles after the initial property load.
-
- Map<String, Object> newlyAddedProperties = cloneProperties();
-
- //remove those that were originally there;
- for (String propName : fileExtractedProperties.keySet())
- newlyAddedProperties.remove(propName);
-
- this.processNewProperties(propertiesDocument,
- newlyAddedProperties);
-
- //write the file.
+ // write the file.
File config = getConfigurationFile();
- FailSafeTransaction trans = this.faService
- .createFailSafeTransaction(config);
- try {
+ FailSafeTransaction trans =
+ this.faService.createFailSafeTransaction(config);
+ try
+ {
trans.beginTransaction();
OutputStream stream = new FileOutputStream(config);
- XMLUtils.indentedWriteXML(
- propertiesDocument, stream);
+
+ store.storeConfiguration(stream);
+
stream.close();
trans.commit();
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
logger.error("can't write data in the configuration file", e);
trans.rollback();
}
}
/**
- * Loads the contents of the specified node and its children into the local
- * properties. Any nodes marked as "system" will also be resolved in the
- * system properties.
- * @param node the root node that we shold load together with its children
- * @param propertyNameBuff a StringBuffer containing the prefix describing
- * the route to the specified node including its one name
- * @param properties the dictionary object where all properties extracted
- * from this node and its children should be recorded.
+ * Returns the configuration file currently used by the implementation.
+ * If there is no such file or this is the first time we reference it
+ * a new one is created.
+ * @return the configuration File currently used by the implementation.
*/
- private void loadNode(Node node,
- StringBuffer propertyNameBuff,
- Map<String, Object> props)
+ private File getConfigurationFile()
+ throws IOException
{
- Node currentNode = null;
- NodeList children = node.getChildNodes();
- for(int i = 0; i < children.getLength(); i++)
+ if (this.configurationFile == null)
{
- currentNode = children.item(i);
+ File configurationFile = getConfigurationFile("xml", false);
- if(currentNode.getNodeType() == Node.ELEMENT_NODE)
+ if (configurationFile == null)
{
- StringBuffer newPropBuff =
- new StringBuffer(propertyNameBuff
- + "." +currentNode.getNodeName());
- String value = XMLConfUtils.getAttribute(
- currentNode, ATTRIBUTE_VALUE);
-
- String propertyType =
- XMLConfUtils.getAttribute(currentNode, SYSTEM_ATTRIBUTE_NAME);
-
- // the value attr is present we must handle the desired property
- if(value != null)
+ /*
+ * Quite strange but let it play out as it did when the
+ * configuration file was in XML format.
+ */
+ this.configurationFile = getConfigurationFile("xml", true);
+ if (!(this.store instanceof XMLConfigurationStore))
+ this.store = new XMLConfigurationStore();
+ }
+ else if (configurationFile.exists())
+ {
+ String name = configurationFile.getName();
+ int extensionBeginIndex = name.lastIndexOf('.');
+ String extension
+ = (extensionBeginIndex > -1)
+ ? name.substring(extensionBeginIndex)
+ : null;
+
+ if (".properties".equalsIgnoreCase(extension))
{
-
- //if the property is marked as "system", we should resolve
- //it against the system properties and only store a
- //reference locally. this is normally done for properties
- //that are supposed to configure underlying libraries.
- if(propertyType != null
- && propertyType.equals(SYSTEM_ATTRIBUTE_TRUE))
+ this.configurationFile = configurationFile;
+ if (!(this.store instanceof PropertyConfigurationStore))
+ this.store = new PropertyConfigurationStore();
+ }
+ else
+ {
+ File newConfigurationFile
+ = new File(
+ configurationFile.getParentFile(),
+ ((extensionBeginIndex > -1)
+ ? name.substring(0, extensionBeginIndex)
+ : name)
+ + ".properties");
+
+ if (newConfigurationFile.exists())
{
- props.put(
- newPropBuff.toString(),
- new PropertyReference(newPropBuff.toString()));
- System.setProperty(newPropBuff.toString(), value);
+ this.configurationFile = newConfigurationFile;
+ if (!(this.store instanceof PropertyConfigurationStore))
+ this.store = new PropertyConfigurationStore();
}
else
{
- props.put(newPropBuff.toString(), value);
+ this.configurationFile = configurationFile;
+ if (!(this.store instanceof XMLConfigurationStore))
+ this.store = new XMLConfigurationStore();
}
}
-
- //load child nodes
- loadNode(currentNode, newPropBuff, props);
}
- }
- }
-
- /**
- * Updates the value of the specified node and its children to reflect those
- * in the properties file. Nodes marked as "system" will be updated from
- * the specified properties object and not from the system properties since
- * if any intentional change (through a configuration form) has occurred
- * it will have been made there.
- *
- * @param node the root node that we shold update together with its children
- * @param propertyNameBuff a StringBuffer containing the prefix describing
- * the dot separated route to the specified node including its one name
- * @param properties the dictionary object where the up to date values of
- * the node should be queried.
- */
- private void updateNode(Node node,
- StringBuffer propertyNameBuff,
- Map<String, Object> props)
- {
- Node currentNode = null;
- NodeList children = node.getChildNodes();
- for(int i = 0; i < children.getLength(); i++)
- {
- currentNode = children.item(i);
-
- if(currentNode.getNodeType() == Node.ELEMENT_NODE)
+ else
{
- StringBuffer newPropBuff =
- new StringBuffer(propertyNameBuff.toString()).append(".")
- .append(currentNode.getNodeName());
-
- Attr attr =
- ((Element)currentNode).getAttributeNode(ATTRIBUTE_VALUE);
-
- if(attr != null)
- {
- //update the corresponding node
- Object value = props.get(newPropBuff.toString());
-
- if(value == null)
- {
- node.removeChild(currentNode);
- continue;
- }
-
- boolean isSystem = value instanceof PropertyReference;
- String prop = isSystem
- ?((PropertyReference)value).getValue().toString()
- :value.toString();
-
- attr.setNodeValue(prop);
-
- //in case the property has changed to system since the last
- //load - update the conf file accordingly.
- if(isSystem)
- ((Element)currentNode).setAttribute(
- SYSTEM_ATTRIBUTE_NAME, SYSTEM_ATTRIBUTE_TRUE);
- else
- ((Element)currentNode).removeAttribute(
- SYSTEM_ATTRIBUTE_NAME);
-
- }
-
- //update child nodes
- updateNode(currentNode, newPropBuff, props);
+ this.configurationFile
+ = getConfigurationFile("properties", true);
+ if (!(this.store instanceof PropertyConfigurationStore))
+ this.store = new PropertyConfigurationStore();
}
- }
- }
-
- /**
- * Returns the configuration file currently used by the implementation.
- * If there is no such file or this is the first time we reference it
- * a new one is created.
- * @return the configuration File currently used by the implementation.
- */
- private File getConfigurationFile()
- {
- if ( configurationFile == null )
- configurationFile = createConfigurationFile();
- return configurationFile;
+ /*
+ * Make sure that the properties SC_HOME_DIR_LOCATION and
+ * SC_HOME_DIR_NAME are available in the store of this instance so
+ * that users don't have to ask the system properties again.
+ */
+ getScHomeDirLocation();
+ getScHomeDirName();
+ }
+ return this.configurationFile;
}
/**
@@ -789,7 +630,10 @@ public class ConfigurationServiceImpl
{
//first let's check whether we already have the name of the directory
//set as a configuration property
- String scHomeDirLocation = getString(PNAME_SC_HOME_DIR_LOCATION);
+ String scHomeDirLocation = null;
+
+ if (store != null)
+ scHomeDirLocation = getString(PNAME_SC_HOME_DIR_LOCATION);
if (scHomeDirLocation == null)
{
@@ -799,14 +643,16 @@ public class ConfigurationServiceImpl
= getSystemProperty(PNAME_SC_HOME_DIR_LOCATION);
if (scHomeDirLocation == null)
- {
scHomeDirLocation = getSystemProperty("user.home");
- }
//now save all this as a configuration property so that we don't
//have to look for it in the sys props next time and so that it is
//available for other bundles to consult.
- properties.put(PNAME_SC_HOME_DIR_LOCATION, scHomeDirLocation);
+ if (store != null)
+ store
+ .setNonSystemProperty(
+ PNAME_SC_HOME_DIR_LOCATION,
+ scHomeDirLocation);
}
return scHomeDirLocation;
@@ -825,7 +671,10 @@ public class ConfigurationServiceImpl
{
//first let's check whether we already have the name of the directory
//set as a configuration property
- String scHomeDirName = getString(PNAME_SC_HOME_DIR_NAME);
+ String scHomeDirName = null;
+
+ if (store != null)
+ scHomeDirName = getString(PNAME_SC_HOME_DIR_NAME);
if (scHomeDirName == null)
{
@@ -835,14 +684,16 @@ public class ConfigurationServiceImpl
= getSystemProperty(PNAME_SC_HOME_DIR_NAME);
if (scHomeDirName == null)
- {
scHomeDirName = ".sip-communicator";
- }
//now save all this as a configuration property so that we don't
//have to look for it in the sys props next time and so that it is
- //available for other bundles to consult.
- properties.put(PNAME_SC_HOME_DIR_NAME, scHomeDirName);
+ // available for other bundles to consult.
+ if (store != null)
+ store
+ .setNonSystemProperty(
+ PNAME_SC_HOME_DIR_NAME,
+ scHomeDirName);
}
return scHomeDirName;
@@ -859,162 +710,120 @@ public class ConfigurationServiceImpl
* we'll look for it in all locations currently present in the $CLASSPATH.
* In case we find it in there we will copy it to the
* $HOME/.sip-communicator directory in case it was in a jar archive and
- * return the reference to the newly created file. In case the file is
- * to be found noweher - a new empty file in the user home directory and
- * returns a link to that one.
- *
- *
+ * return the reference to the newly created file. In case the file is to be
+ * found nowhere - a new empty file in the user home directory and returns a
+ * link to that one.
+ *
+ * @param extension
+ * the extension of the file name of the configuration file. The
+ * specified extension may not be taken into account if the the
+ * configuration file name is forced through a system property.
+ * @param create
+ * <tt>true</tt> to create the configuration file with the
+ * determined file name if it does not exist; <tt>false</tt> to
+ * only figure out the file name of the configuration file
+ * without creating it
* @return the configuration file currently used by the implementation.
*/
- File createConfigurationFile()
+ private File getConfigurationFile(String extension, boolean create)
+ throws IOException
{
- try
- {
- //see whether we have a user specified name for the conf file
- String pFileName = getSystemProperty(
- FILE_NAME_PROPERTY);
- if (pFileName == null)
- {
- pFileName = "sip-communicator.xml";
- }
-
- // try to open the file in current directory
- File configFileInCurrentDir = new File(pFileName);
- if (configFileInCurrentDir.exists())
- {
- logger.debug("Using config file in current dir: "
- + configFileInCurrentDir.getCanonicalPath());
- return configFileInCurrentDir;
- }
+ //see whether we have a user specified name for the conf file
+ String pFileName = getSystemProperty(FILE_NAME_PROPERTY);
+ if (pFileName == null)
+ pFileName = "sip-communicator." + extension;
- // we didn't find it in ".", try the SIP Communicator home directory
- // first check whether a custom SC home directory is specified
-
- //name of the sip-communicator home directory
- String scHomeDirName = getScHomeDirName();
-
- //location of the sip-communicator home directory
- String scHomeDirLocation = getScHomeDirLocation();
-
- File configDir = new File( scHomeDirLocation
- + File.separator + scHomeDirName);
+ // try to open the file in current directory
+ File configFileInCurrentDir = new File(pFileName);
+ if (configFileInCurrentDir.exists())
+ {
+ logger.debug(
+ "Using config file in current dir: "
+ + configFileInCurrentDir.getAbsolutePath());
+ return configFileInCurrentDir;
+ }
- File configFileInUserHomeDir =
- new File(configDir, pFileName);
+ // we didn't find it in ".", try the SIP Communicator home directory
+ // first check whether a custom SC home directory is specified
- if (configFileInUserHomeDir.exists())
- {
- logger.debug("Using config file in $HOME/.sip-communicator: "
- + configFileInCurrentDir.getCanonicalPath());
- return configFileInUserHomeDir;
- }
+ File configDir
+ = new File(
+ getScHomeDirLocation()
+ + File.separator
+ + getScHomeDirName());
+ File configFileInUserHomeDir = new File(configDir, pFileName);
- // If we are in a jar - copy config file from jar to user home.
- logger.trace("Copying config file.");
+ if (configFileInUserHomeDir.exists())
+ {
+ logger.debug(
+ "Using config file in $HOME/.sip-communicator: "
+ + configFileInUserHomeDir.getAbsolutePath());
+ return configFileInUserHomeDir;
+ }
- configDir.mkdirs();
- InputStream in = getClass().getClassLoader().
- getResourceAsStream(pFileName);
+ // If we are in a jar - copy config file from jar to user home.
+ InputStream in
+ = getClass().getClassLoader().getResourceAsStream(pFileName);
- //Return an empty file if there wasn't any in the jar
- //null check report from John J. Barton - IBM
- if (in == null)
+ //Return an empty file if there wasn't any in the jar
+ //null check report from John J. Barton - IBM
+ if (in == null)
+ {
+ if (create)
{
+ configDir.mkdirs();
configFileInUserHomeDir.createNewFile();
- logger.debug("Created an empty file in $HOME: "
- + configFileInCurrentDir.getCanonicalPath());
- return configFileInUserHomeDir;
- }
- BufferedReader reader =
- new BufferedReader(new InputStreamReader(in));
-
- PrintWriter writer = new PrintWriter(new FileWriter(
- configFileInUserHomeDir));
-
- String line = null;
- logger.debug("Copying properties file:");
- while ( (line = reader.readLine()) != null)
- {
- writer.println(line);
- logger.debug(line);
}
- writer.flush();
+ logger.debug(
+ "Created an empty file in $HOME: "
+ + configFileInUserHomeDir.getAbsolutePath());
return configFileInUserHomeDir;
}
- catch (IOException ex)
+
+ logger.trace(
+ "Copying config file from JAR into "
+ + configFileInUserHomeDir.getAbsolutePath());
+ configDir.mkdirs();
+ try
{
- logger.error("Error creating config file", ex);
- return null;
+ copy(in, configFileInUserHomeDir);
}
- }
-
- /**
- * Creates new entries in the XML <tt>doc</tt> for every element in the
- * <tt>newProperties</tt> table.
- *
- * @param doc the XML <tt>Document</tt> where the new entries should be
- * created
- * @param newProperties the table containing the properties that are to be
- * introduced in the document.
- */
- private void processNewProperties(Document doc,
- Map<String, Object> newProperties)
- {
- for (Map.Entry<String, Object> entry : newProperties.entrySet())
+ finally
{
- String key = entry.getKey();
- Object value = entry.getValue();
- boolean isSystem = value instanceof PropertyReference;
- value = isSystem
- ?((PropertyReference)value).getValue()
- :value;
- processNewProperty(doc, key, value.toString(), isSystem);
+ try
+ {
+ in.close();
+ }
+ catch (IOException ioex)
+ {
+ /*
+ * Ignore it because it doesn't matter and, most importantly, it
+ * shouldn't prevent us from using the configuration file.
+ */
+ }
}
+ return configFileInUserHomeDir;
}
- /**
- * Creates an entry in the xml <tt>doc</tt> for the specified key value
- * pair.
- * @param doc the XML <tt>document</tt> to update.
- * @param key the value of the <tt>name</tt> attribute for the new entry
- * @param value the value of the <tt>value</tt> attribue for the new
- * @param isSystem specifies whether this is a system property (system
- * attribute will be set to true).
- * entry.
- */
- private void processNewProperty(Document doc,
- String key,
- String value,
- boolean isSystem)
+ private static void copy(InputStream inputStream, File outputFile)
+ throws IOException
{
- StringTokenizer tokenizer = new StringTokenizer(key, ".");
- String[] toks = new String[tokenizer.countTokens()];
- int i = 0;
- while(tokenizer.hasMoreTokens())
- toks[i++] = tokenizer.nextToken();
-
- String[] chain = new String[toks.length - 1];
- for (int j = 0; j < chain.length; j++)
- {
- chain[j] = toks[j];
- }
+ OutputStream outputStream = new FileOutputStream(outputFile);
- String nodeName = toks[toks.length - 1];
+ try
+ {
+ byte[] bytes = new byte[4 * 1024];
+ int bytesRead;
- Element parent = XMLConfUtils.createLastPathComponent(doc, chain);
- Element newNode = XMLConfUtils.findChild(parent, nodeName);
- if (newNode == null)
+ while ((bytesRead = inputStream.read(bytes)) != -1)
+ outputStream.write(bytes, 0, bytesRead);
+ }
+ finally
{
- newNode = doc.createElement(nodeName);
- parent.appendChild(newNode);
+ outputStream.close();
}
- newNode.setAttribute("value", value);
-
- if(isSystem)
- newNode.setAttribute(SYSTEM_ATTRIBUTE_NAME, SYSTEM_ATTRIBUTE_TRUE);
}
-
/**
* Returns the value of the specified java system property. In case the
* value was a zero length String or one that only contained whitespaces,
@@ -1028,13 +837,8 @@ public class ConfigurationServiceImpl
private static String getSystemProperty(String propertyName)
{
String retval = System.getProperty(propertyName);
- if (retval == null){
- return retval;
- }
-
- if (retval.trim().length() == 0){
- return null;
- }
+ if ((retval != null) && (retval.trim().length() == 0))
+ retval = null;
return retval;
}
@@ -1093,59 +897,6 @@ public class ConfigurationServiceImpl
}
/**
- * We use property references when we'd like to store system properties.
- * Simply storing System properties in our properties Map would not be
- * enough since it will lead to mismatching values for the same property in
- * the System property set and in our local set of properties. Storing them
- * only in the System property set OTOH is a bit clumsy since it obliges
- * bundles to use to different configuration property sources. For that
- * reason, every time we get handed a property labeled as System, in stead
- * of storing its actual value in the local property set we store a
- * PropertyReference instance that will retrive it from the system
- * properties when necessary.
- */
- private static class PropertyReference
- {
- private final String propertyName;
-
- PropertyReference(String propertyName)
- {
- this.propertyName = propertyName;
- }
-
- /**
- * Return the actual value of the property as recorded in the System
- * properties.
- * @return the valued of the property as recorded in the System props.
- */
- public Object getValue()
- {
- return System.getProperty(propertyName);
- }
- }
-
- /**
- * Returns a copy of the Map containing all configuration properties
- * @return a Map clone of the current configuration property set.
- */
- private Map<String, Object> cloneProperties()
- {
- // at the time I'm writing this method we're implementing the
- // configuration service through the use of a hashtable. this may very
- // well change one day so let's not be presumptuous
- if (properties instanceof Hashtable)
- return (Map<String, Object>) ((Hashtable) properties).clone();
- if (properties instanceof HashMap)
- return (Map<String, Object>) ((HashMap) properties).clone();
- if (properties instanceof TreeMap)
- return (Map<String, Object>) ((TreeMap) properties).clone();
-
- // well you can't say that I didn't try!!!
-
- return new Hashtable<String, Object>(properties);
- }
-
- /**
* Determines whether the property with the specified
* <tt>propertyName</tt> has been previously declared as System
*
@@ -1157,8 +908,7 @@ public class ConfigurationServiceImpl
*/
private boolean isSystem(String propertyName)
{
- return properties.containsKey(propertyName)
- && properties.get(propertyName) instanceof PropertyReference;
+ return store.isSystem(propertyName);
}
/**
@@ -1166,7 +916,7 @@ public class ConfigurationServiceImpl
*/
public void purgeStoredConfiguration()
{
- if (this.configurationFile != null)
+ if (configurationFile != null)
{
configurationFile.delete();
configurationFile = null;
@@ -1182,8 +932,8 @@ public class ConfigurationServiceImpl
{
if (logger.isDebugEnabled())
{
- Properties pValues = System.getProperties();
- for (Map.Entry<Object, Object> entry : pValues.entrySet())
+ for (Map.Entry<Object, Object> entry
+ : System.getProperties().entrySet())
logger.debug(entry.getKey() + "=" + entry.getValue());
}
}
@@ -1195,7 +945,7 @@ public class ConfigurationServiceImpl
* loads their contents as system properties. All such files have to be in
* a location that's in the classpath.
*/
- public void preloadSystemPropertyFiles()
+ private void preloadSystemPropertyFiles()
{
String propertyFilesListStr
= System.getProperty( SYS_PROPS_FILE_NAME_PROPERTY );
diff --git a/src/net/java/sip/communicator/impl/notification/NotificationServiceImpl.java b/src/net/java/sip/communicator/impl/notification/NotificationServiceImpl.java
index 5d25742..7ffdb7b 100644
--- a/src/net/java/sip/communicator/impl/notification/NotificationServiceImpl.java
+++ b/src/net/java/sip/communicator/impl/notification/NotificationServiceImpl.java
@@ -491,7 +491,6 @@ public class NotificationServiceImpl
configService.setProperty(
eventTypeNodeName + ".active",
Boolean.toString(isActive));
-
return;
}
@@ -510,6 +509,8 @@ public class NotificationServiceImpl
actionTypeNodeName = actionTypeRootPropName;
}
+ Map<String, Object> configProperties = new HashMap<String, Object>();
+
// If we didn't find the given actionType in the configuration we save
// it here.
if(actionTypeNodeName == null)
@@ -518,7 +519,7 @@ public class NotificationServiceImpl
+ ".actionType"
+ Long.toString(System.currentTimeMillis());
- configService.setProperty(actionTypeNodeName, actionType);
+ configProperties.put(actionTypeNodeName, actionType);
}
if(actionHandler instanceof SoundNotificationHandler)
@@ -526,19 +527,19 @@ public class NotificationServiceImpl
SoundNotificationHandler soundHandler
= (SoundNotificationHandler) actionHandler;
- configService.setProperty(
+ configProperties.put(
actionTypeNodeName + ".soundFileDescriptor",
soundHandler.getDescriptor());
- configService.setProperty(
+ configProperties.put(
actionTypeNodeName + ".loopInterval",
soundHandler.getLoopInterval());
- configService.setProperty(
+ configProperties.put(
actionTypeNodeName + ".enabled",
Boolean.toString(isActive));
- configService.setProperty(
+ configProperties.put(
actionTypeNodeName + ".default",
Boolean.toString(isDefault));
}
@@ -547,15 +548,15 @@ public class NotificationServiceImpl
PopupMessageNotificationHandler messageHandler
= (PopupMessageNotificationHandler) actionHandler;
- configService.setProperty(
+ configProperties.put(
actionTypeNodeName + ".defaultMessage",
messageHandler.getDefaultMessage());
- configService.setProperty(
+ configProperties.put(
actionTypeNodeName + ".enabled",
Boolean.toString(isActive));
- configService.setProperty(
+ configProperties.put(
actionTypeNodeName + ".default",
Boolean.toString(isDefault));
}
@@ -564,15 +565,15 @@ public class NotificationServiceImpl
LogMessageNotificationHandler logMessageHandler
= (LogMessageNotificationHandler) actionHandler;
- configService.setProperty(
+ configProperties.put(
actionTypeNodeName + ".logType",
logMessageHandler.getLogType());
- configService.setProperty(
+ configProperties.put(
actionTypeNodeName + ".enabled",
Boolean.toString(isActive));
- configService.setProperty(
+ configProperties.put(
actionTypeNodeName + ".default",
Boolean.toString(isDefault));
}
@@ -581,18 +582,21 @@ public class NotificationServiceImpl
CommandNotificationHandler commandHandler
= (CommandNotificationHandler) actionHandler;
- configService.setProperty(
+ configProperties.put(
actionTypeNodeName + ".commandDescriptor",
commandHandler.getDescriptor());
- configService.setProperty(
+ configProperties.put(
actionTypeNodeName + ".enabled",
Boolean.toString(isActive));
- configService.setProperty(
+ configProperties.put(
actionTypeNodeName + ".default",
Boolean.toString(isDefault));
}
+
+ if (configProperties.size() > 0)
+ configService.setProperties(configProperties);
}
/**
diff --git a/src/net/java/sip/communicator/impl/protocol/AccountManagerImpl.java b/src/net/java/sip/communicator/impl/protocol/AccountManagerImpl.java
index 3002fc0..ddd7b23 100644
--- a/src/net/java/sip/communicator/impl/protocol/AccountManagerImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/AccountManagerImpl.java
@@ -517,6 +517,9 @@ public class AccountManagerImpl
}
}
+ Map<String, Object> configurationProperties
+ = new HashMap<String, Object>();
+
// Create a unique node name of the properties node that will contain
// this account's properties.
if (accountNodeName == null)
@@ -525,13 +528,13 @@ public class AccountManagerImpl
// set a value for the persistent node so that we could later
// retrieve it as a property
- configurationService.setProperty(factoryPackage // prefix
+ configurationProperties.put(factoryPackage // prefix
+ "." + accountNodeName, accountNodeName);
// register the account in the configuration service.
// we register all the properties in the following hierarchy
//net.java.sip.communicator.impl.protocol.PROTO_NAME.ACC_ID.PROP_NAME
- configurationService.setProperty(factoryPackage// prefix
+ configurationProperties.put(factoryPackage// prefix
+ "." + accountNodeName // node name for the account id
+ "." + ProtocolProviderFactory.ACCOUNT_UID, // propname
accountID.getAccountUniqueID()); // value
@@ -549,12 +552,15 @@ public class AccountManagerImpl
if (property.equals(ProtocolProviderFactory.PASSWORD))
value = new String(Base64.encode(value.getBytes()));
- configurationService.setProperty(factoryPackage // prefix
- + "." + accountNodeName // a uniew node name for the account id
+ configurationProperties.put(factoryPackage // prefix
+ + "." + accountNodeName // a unique node name for the account id
+ "." + property, // propname
value); // value
}
+ if (configurationProperties.size() > 0)
+ configurationService.setProperties(configurationProperties);
+
logger.debug("Stored account for id " + accountID.getAccountUniqueID()
+ " for package " + factoryPackage);
}
diff --git a/src/net/java/sip/communicator/service/configuration/ConfigurationService.java b/src/net/java/sip/communicator/service/configuration/ConfigurationService.java
index 6ded4de..36ee67d 100644
--- a/src/net/java/sip/communicator/service/configuration/ConfigurationService.java
+++ b/src/net/java/sip/communicator/service/configuration/ConfigurationService.java
@@ -77,6 +77,9 @@ public interface ConfigurationService
boolean isSystem)
throws PropertyVetoException;
+ public void setProperties(Map<String, Object> properties)
+ throws PropertyVetoException;
+
/**
* Returns the value of the property with the specified name or null if no
* such property exists.
diff --git a/src/net/java/sip/communicator/service/configuration/PropertyVetoException.java b/src/net/java/sip/communicator/service/configuration/PropertyVetoException.java
index fad5b1a..b6bd5d8 100644
--- a/src/net/java/sip/communicator/service/configuration/PropertyVetoException.java
+++ b/src/net/java/sip/communicator/service/configuration/PropertyVetoException.java
@@ -21,18 +21,19 @@ public class PropertyVetoException
* A PropertyChangeEvent describing the vetoed change.
* @serial
*/
- private PropertyChangeEvent evt;
+ private final PropertyChangeEvent evt;
/**
* Constructs a <tt>PropertyVetoException</tt> with a
* detailed message.
*
- * @param mess Descriptive message
+ * @param message Descriptive message
* @param evt A PropertyChangeEvent describing the vetoed change.
*/
- public PropertyVetoException(String mess, PropertyChangeEvent evt)
+ public PropertyVetoException(String message, PropertyChangeEvent evt)
{
- super(mess);
+ super(message);
+
this.evt = evt;
}