New command for importing a single domain from a file

The command is used as follows:

    importDomainWithSettingsXML <file path> [overwrite]

It reads the file given as first argument (path must be absolute) and imports
the domain found in it.

It does not check whether it overlaps with another domain (same elements in two
domains). It does, however, check if there is an existing domain with the same
name as the one being imported. If so and if the (optional) second argument
is "overwrite", it will first delete the existing domain; if not it will refuse
to import the new domain.

Change-Id: I7aaa225f2f1a296f52dc8a97f55e1ff70c06d567
Signed-off-by: David Wagner <david.wagner@intel.com>
diff --git a/parameter/ConfigurableDomain.cpp b/parameter/ConfigurableDomain.cpp
index bdcddd4..35acb9c 100644
--- a/parameter/ConfigurableDomain.cpp
+++ b/parameter/ConfigurableDomain.cpp
@@ -40,6 +40,11 @@
 
 using std::string;
 
+CConfigurableDomain::CConfigurableDomain() :
+    _bSequenceAware(false), _pLastAppliedConfiguration(NULL)
+{
+}
+
 CConfigurableDomain::CConfigurableDomain(const string& strName) : base(strName), _bSequenceAware(false), _pLastAppliedConfiguration(NULL)
 {
 }
@@ -215,6 +220,8 @@
     // Sequence awareness (optional)
     _bSequenceAware = xmlElement.hasAttribute("SequenceAware") && xmlElement.getAttributeBoolean("SequenceAware");
 
+    setName(xmlElement.getAttributeString("Name"));
+
     // Local parsing. Do not dig
     if (!parseDomainConfigurations(xmlElement, xmlDomainImportContext) ||
         !parseConfigurableElements(xmlElement, xmlDomainImportContext) ||
diff --git a/parameter/ConfigurableDomain.h b/parameter/ConfigurableDomain.h
index 084c187..a29c1ba 100644
--- a/parameter/ConfigurableDomain.h
+++ b/parameter/ConfigurableDomain.h
@@ -48,6 +48,7 @@
     typedef std::list<CConfigurableElement*>::const_iterator ConfigurableElementListIterator;
     typedef std::map<const CConfigurableElement*, CSyncerSet*>::const_iterator ConfigurableElementToSyncerSetMapIterator;
 public:
+    CConfigurableDomain();
     CConfigurableDomain(const std::string& strName);
     virtual ~CConfigurableDomain();
 
diff --git a/parameter/ConfigurableDomains.cpp b/parameter/ConfigurableDomains.cpp
index 8dff45a..b77e2aa 100644
--- a/parameter/ConfigurableDomains.cpp
+++ b/parameter/ConfigurableDomains.cpp
@@ -127,24 +127,50 @@
     return true;
 }
 
+bool CConfigurableDomains::addDomain(CConfigurableDomain& domain, bool bOverwrite,
+                                     string& strError)
+{
+    string strErrorDrop;
+
+    string strDomainName(domain.getName());
+    CConfigurableDomain* pExistingDomain = findConfigurableDomain(strDomainName, strErrorDrop);
+
+    if (pExistingDomain) {
+        if (!bOverwrite) {
+            strError = "Can't add domain \"" + strDomainName +
+                "\" because it already exists and overwrite was not requested.";
+            return false;
+        }
+
+        deleteDomain(*pExistingDomain);
+    }
+
+    log_info("Adding configurable domain \"" + strDomainName + "\"");
+
+    addChild(&domain);
+
+    return true;
+}
+
+void CConfigurableDomains::deleteDomain(CConfigurableDomain& configurableDomain)
+{
+    log_info("Deleting configurable domain \"" + configurableDomain.getName() + "\"");
+
+    removeChild(&configurableDomain);
+
+    delete &configurableDomain;
+}
+
 bool CConfigurableDomains::deleteDomain(const string& strName, string& strError)
 {
     CConfigurableDomain* pConfigurableDomain = findConfigurableDomain(strName, strError);
 
-    if (!pConfigurableDomain) {
-
-        return false;
+    if (pConfigurableDomain) {
+        deleteDomain(*pConfigurableDomain);
+        return true;
     }
 
-    log_info("Deleting configurable domain \"%s\"", strName.c_str());
-
-    // Hierarchy
-    removeChild(pConfigurableDomain);
-
-    // Destroy
-    delete pConfigurableDomain;
-
-    return true;
+    return false;
 }
 
 void CConfigurableDomains::deleteAllDomains()
diff --git a/parameter/ConfigurableDomains.h b/parameter/ConfigurableDomains.h
index 8016cb9..3cc16df 100644
--- a/parameter/ConfigurableDomains.h
+++ b/parameter/ConfigurableDomains.h
@@ -49,6 +49,30 @@
     // Configuration/Domains handling
     /// Domains
     bool createDomain(const std::string& strName, std::string& strError);
+
+    /*
+     * Adds a domain object to configurable domains. The ConfigurableDomains
+     * object takes ownership of the ConfigurableDomain object.
+     *
+     * @param[in] pDomain the domain object.
+     * @param[in] bOverwrite if false, will refuse to overwrite an existing
+     * domain, otherwise, an existing domain with the same name will first be
+     * removed.
+     * @param[in,out] strError error message
+     *
+     * @returns true if the domain was successfully added
+     */
+    bool addDomain(CConfigurableDomain& domain, bool bOverwrite, std::string& strError);
+
+    /**
+     * Delete a domain by name
+     *
+     * @param[in] strName name of the domain to be deleted
+     * @param[in,out] strError error message
+     *
+     * @returns true of the domain was sucessfully deleted, false otherwise (i.e.
+     * the domain didn't exist).
+     */
     bool deleteDomain(const std::string& strName, std::string& strError);
     void deleteAllDomains();
     bool renameDomain(const std::string& strName, const std::string& strNewName, std::string& strError);
@@ -105,6 +129,14 @@
     // Class kind
     virtual std::string getKind() const;
 private:
+    /** Delete a domain
+     *
+     * @param(in] configurableDomain domain to be deleted
+     * @param[in,out] strError error message
+     * @returns true of the domain was sucessfully deleted, false otherwise (i.e.
+     * the domain didn't exist).
+     */
+    void deleteDomain(CConfigurableDomain& configurableDomain);
     // Returns true if children dynamic creation is to be dealt with
     virtual bool childrenAreDynamic() const;
     // Gather owned configurable elements owned by any domain
diff --git a/parameter/ParameterMgr.cpp b/parameter/ParameterMgr.cpp
index 9b01c85..84a3fd4 100644
--- a/parameter/ParameterMgr.cpp
+++ b/parameter/ParameterMgr.cpp
@@ -89,6 +89,7 @@
 #include "XmlMemoryDocSource.h"
 #include "Utility.h"
 #include <sstream>
+#include <memory>
 
 #define base CElement
 
@@ -259,6 +260,11 @@
     { "importDomainsWithSettingsXML",
             &CParameterMgr::importConfigurableDomainsWithSettingsFromXMLCommmandProcess, 1,
             "<file path>", "Import domains including settings from XML file" },
+    { "importDomainWithSettingsXML",
+            &CParameterMgr::importConfigurableDomainWithSettingsFromXMLCommmandProcess, 1,
+            "<file path> [overwrite]", "Import a single domain including settings from XML file."
+            " Does not overwrite an existing domain unless 'overwrite' is passed as second"
+            " argument" },
     { "exportSettings", &CParameterMgr::exportSettingsCommmandProcess, 1,
             "<file path>", "Export settings to binary file" },
     { "importSettings", &CParameterMgr::importSettingsCommmandProcess, 1,
@@ -654,6 +660,38 @@
     return true;
 }
 
+bool CParameterMgr::importDomainFromFile(const string& strXmlFilePath, bool bOverwrite,
+                                         string& strError)
+{
+    CXmlDomainImportContext xmlDomainImportContext(strError, true, *getSystemClass());
+
+    // Selection criteria definition for rule creation
+    xmlDomainImportContext.setSelectionCriteriaDefinition(
+            getConstSelectionCriteria()->getSelectionCriteriaDefinition());
+
+    // Auto validation of configurations
+    xmlDomainImportContext.setAutoValidationRequired(true);
+
+    // We initialize the domain with an empty name but since we have set the isDomainStandalone
+    // context, the name will be retrieved during de-serialization
+    std::auto_ptr<CConfigurableDomain> standaloneDomain(new CConfigurableDomain());
+    bool bSuccess = xmlParse(xmlDomainImportContext, standaloneDomain.get(),
+                             strXmlFilePath, "", EParameterConfigurationLibrary, "");
+
+    if (!bSuccess) {
+        return false;
+    }
+
+    bSuccess = getConfigurableDomains()->addDomain(*standaloneDomain, bOverwrite, strError);
+    if (!bSuccess) {
+        return false;
+    }
+
+    // ownership has been transfered to the ConfigurableDomains object
+    standaloneDomain.release();
+    return true;
+}
+
 // XML parsing
 bool CParameterMgr::xmlParse(CXmlElementSerializingContext& elementSerializingContext, CElement* pRootElement, const string& strXmlFilePath, const string& strXmlFolder, CParameterMgr::ElementLibrary eElementLibrary, const string& strNameAttrituteName)
 {
@@ -664,17 +702,25 @@
     // Get Schema file associated to root element
     string strXmlSchemaFilePath = _strSchemaFolderLocation + "/" + pRootElement->getKind() + ".xsd";
 
-    CXmlFileDocSource fileDocSource(strXmlFilePath, strXmlSchemaFilePath,
-                                    pRootElement->getKind(),
-                                    pRootElement->getName(), strNameAttrituteName,
-                                    _bValidateSchemasOnStart);
+    std::auto_ptr<CXmlFileDocSource> fileDocSource(NULL);
+
+    if (strNameAttrituteName.empty()) {
+        fileDocSource.reset(new CXmlFileDocSource(strXmlFilePath, strXmlSchemaFilePath,
+                                                pRootElement->getKind(),
+                                                _bValidateSchemasOnStart));
+    } else {
+        fileDocSource.reset(new CXmlFileDocSource(strXmlFilePath, strXmlSchemaFilePath,
+                                               pRootElement->getKind(),
+                                               pRootElement->getName(), strNameAttrituteName,
+                                               _bValidateSchemasOnStart));
+    }
 
     // Start clean
     pRootElement->clean();
 
     CXmlMemoryDocSink memorySink(pRootElement);
 
-    if (!memorySink.process(fileDocSource, elementSerializingContext)) {
+    if (!memorySink.process(*fileDocSource, elementSerializingContext)) {
         //Cleanup
         pRootElement->clean();
 
@@ -1519,6 +1565,26 @@
     return importDomainsXml(remoteCommand.getArgument(0), true, true, strResult) ? CCommandHandler::EDone : CCommandHandler::EFailed;
 }
 
+CParameterMgr::CCommandHandler::CommandStatus CParameterMgr::importConfigurableDomainWithSettingsFromXMLCommmandProcess(const IRemoteCommand& remoteCommand, string& strResult)
+{
+    bool bOverwrite = false;
+
+    // Look for optional arguments
+    if (remoteCommand.getArgumentCount() > 1) {
+
+        if (remoteCommand.getArgument(1) == "overwrite") {
+
+            bOverwrite = true;
+        } else {
+            // Show usage
+            return CCommandHandler::EShowUsage;
+        }
+    }
+
+    return importSingleDomainXml(remoteCommand.getArgument(0), bOverwrite, strResult) ?
+        CCommandHandler::EDone : CCommandHandler::EFailed;
+}
+
 CParameterMgr::CCommandHandler::CommandStatus CParameterMgr::exportSettingsCommmandProcess(const IRemoteCommand& remoteCommand, string& strResult)
 {
     return exportDomainsBinary(remoteCommand.getArgument(0), strResult) ? CCommandHandler::EDone : CCommandHandler::EFailed;
@@ -2085,6 +2151,25 @@
     return bProcessSuccess;
 }
 
+bool CParameterMgr::importSingleDomainXml(const string& strXmlSource, bool bOverwrite,
+                                          string& strError)
+{
+    if (!checkTuningModeOn(strError)) {
+
+        return false;
+    }
+
+    // check path is absolute
+    if (strXmlSource[0] != '/') {
+
+        strError = "Please provide absolute path";
+
+        return false;
+    }
+
+    return importDomainFromFile(strXmlSource, bOverwrite, strError);
+}
+
 bool CParameterMgr::serializeElement(string& strXmlDest,
                                      CXmlSerializingContext& xmlSerializingContext, bool bToFile,
                                      const CElement& element, string& strError) const
@@ -2269,7 +2354,7 @@
     // Parameter Configuration Domains creation
     CElementLibrary* pParameterConfigurationLibrary = new CElementLibrary;
 
-    pParameterConfigurationLibrary->addElementBuilder("ConfigurableDomain", new TNamedElementBuilderTemplate<CConfigurableDomain>());
+    pParameterConfigurationLibrary->addElementBuilder("ConfigurableDomain", new TElementBuilderTemplate<CConfigurableDomain>());
     pParameterConfigurationLibrary->addElementBuilder("Configuration", new TNamedElementBuilderTemplate<CDomainConfiguration>());
     pParameterConfigurationLibrary->addElementBuilder("CompoundRule", new TElementBuilderTemplate<CCompoundRule>());
     pParameterConfigurationLibrary->addElementBuilder("SelectionCriterionRule", new TElementBuilderTemplate<CSelectionCriterionRule>());
diff --git a/parameter/ParameterMgr.h b/parameter/ParameterMgr.h
index cd1c468..7962294 100644
--- a/parameter/ParameterMgr.h
+++ b/parameter/ParameterMgr.h
@@ -250,6 +250,31 @@
     bool importDomainsXml(const std::string& strXmlSource, bool bWithSettings, bool bFromFile,
                           std::string& strError);
 
+    /**
+      * Method that imports a single Configurable Domain from an Xml source.
+      *
+      * @param[in] strXmlSource a string containing an xml description or a path to an xml file
+      * @param[in] bWithSettings a boolean that determines if the settings should be used in the
+      * xml description
+      * @param[in] bFromFile a boolean that determines if the source is an xml description in
+      * strXmlSource or contained in a file. In that case strXmlSource is just the file path.
+      * @param[out] strError is used as the error output
+      *
+      * @return false if any error occurs
+      */
+    bool importSingleDomainXml(const std::string& strXmlSource, bool bOverwrite,
+                               std::string& strError);
+
+    /**
+      * Method that imports a single Configurable Domain, with settings, from an Xml file.
+      *
+      * @param[in] strXmlFilePath absolute path to the xml file containing the domain
+      * @param[out] strError is used as the error output
+      *
+      * @return false if any error occurs
+      */
+    bool importDomainFromFile(const std::string& strXmlFilePath, bool bOverwrite, std::string& strError);
+
 
     /**
      * Export an element object to an Xml destination.
@@ -398,6 +423,7 @@
     CCommandHandler::CommandStatus importConfigurableDomainsFromXMLCommmandProcess(const IRemoteCommand& remoteCommand, std::string& strResult);
     CCommandHandler::CommandStatus exportConfigurableDomainsWithSettingsToXMLCommmandProcess(const IRemoteCommand& remoteCommand, std::string& strResult);
     CCommandHandler::CommandStatus importConfigurableDomainsWithSettingsFromXMLCommmandProcess(const IRemoteCommand& remoteCommand, std::string& strResult);
+    CCommandHandler::CommandStatus importConfigurableDomainWithSettingsFromXMLCommmandProcess(const IRemoteCommand& remoteCommand, std::string& strResult);
     CCommandHandler::CommandStatus exportSettingsCommmandProcess(const IRemoteCommand& remoteCommand, std::string& strResult);
     CCommandHandler::CommandStatus importSettingsCommmandProcess(const IRemoteCommand& remoteCommand, std::string& strResult);