From 8f05c7de54336daefb214a754de35367098b6510 Mon Sep 17 00:00:00 2001
From: Adrian Kummerlaender
Date: Mon, 7 Jul 2014 22:25:03 +0200
Subject: Implemented custom xercesc::DOMDocument deleter * pointers to
 xercesc::DOMDocument were manually released ** this is now solved using a
 custom deleter for the appropriate std::unqiue_ptr template specialization *
 added matching factory method to DomDocumentCache * updated external function
 implementations accordingly ** "constructDocument" is now expected to return
 a DomDocumentCache::document_ptr instance * updated TransformerFacade
 accordingly * this change was implemented to get rid of the manual memory
 management required by xalan / xerces

---
 ixslt.cc                                |  6 +++---
 src/function/external_text_formatter.cc | 20 ++++++++------------
 src/function/external_text_formatter.h  |  2 +-
 src/function/read_directory.cc          | 18 +++++-------------
 src/function/read_directory.h           |  3 ++-
 src/function/read_file.cc               | 20 ++++++++------------
 src/function/read_file.h                |  3 ++-
 src/function/transform.cc               | 18 +++++-------------
 src/function/transform.h                |  2 +-
 src/function/write_file.cc              | 23 +++++++----------------
 src/function/write_file.h               |  2 +-
 src/support/dom/document_cache.cc       | 28 ++++++++++++++++++++++++++--
 src/support/dom/document_cache.h        | 15 ++++++++++++++-
 src/support/dom/document_cache_item.cc  | 10 +++-------
 src/support/dom/document_cache_item.h   |  6 ++----
 src/transformer_facade.cc               | 24 +++++++-----------------
 16 files changed, 95 insertions(+), 105 deletions(-)

diff --git a/ixslt.cc b/ixslt.cc
index 048f990..610d28f 100644
--- a/ixslt.cc
+++ b/ixslt.cc
@@ -100,10 +100,10 @@ bool generate(
 	std::basic_ostream<char>&         target,
 	Arguments&&...                    arguments
 ) {
-	InputXSLT::TransformerFacade transformer(resolver);
-	WarningGuard guard(&transformer);
-
 	try {
+		InputXSLT::TransformerFacade transformer(resolver);
+		WarningGuard guard(&transformer);
+
 		xalan::XalanStdOutputStream         output(target);
 		xalan::XalanOutputStreamPrintWriter writer(output);
 		xalan::FormatterToXML               formatter(writer);
diff --git a/src/function/external_text_formatter.cc b/src/function/external_text_formatter.cc
index e7ab1a2..a86c71b 100644
--- a/src/function/external_text_formatter.cc
+++ b/src/function/external_text_formatter.cc
@@ -2,9 +2,6 @@
 
 #include <xalanc/XSLT/XSLTInputSource.hpp>
 
-#include <xercesc/dom/DOMDocument.hpp>
-#include <xercesc/dom/DOMImplementation.hpp>
-#include <xercesc/dom/DOMElement.hpp>
 #include <xercesc/parsers/XercesDOMParser.hpp>
 
 #include <boost/process.hpp>
@@ -42,16 +39,12 @@ inline xercesc::DOMNode* importDocumentElement(
 
 namespace InputXSLT {
 
-xercesc::DOMDocument* FunctionExternalTextFormatter::constructDocument(
+DomDocumentCache::document_ptr FunctionExternalTextFormatter::constructDocument(
 	boost::filesystem::path formatterPath,
 	std::string             stdinText
 ) {
-	xercesc::DOMDocument* const domDocument(
-		xercesc::DOMImplementation::getImplementation()->createDocument(
-			nullptr,
-			*XercesStringGuard<XMLCh>("content"),
-			nullptr
-		)
+	DomDocumentCache::document_ptr domDocument(
+		DomDocumentCache::createDocument()
 	);
 
 	xercesc::DOMNode* const rootNode(
@@ -78,14 +71,17 @@ xercesc::DOMDocument* FunctionExternalTextFormatter::constructDocument(
 
 	boost::process::status status = formatterProcess.wait();
 
-	ResultNodeFacade result(domDocument, rootNode, "output");
+	ResultNodeFacade result(domDocument.get(), rootNode, "output");
 	result.setAttribute("formatter", formatterPath.filename().string());
 	result.setAttribute("code",      std::to_string(status.exit_status()));
 
 	if ( status.exited() ) {
 		try {
 			result.setContent(
-				importDocumentElement(outputStream, domDocument)->getChildNodes()
+				importDocumentElement(
+					outputStream,
+					domDocument.get()
+				)->getChildNodes()
 			);
 
 			result.setAttribute("result", "success");
diff --git a/src/function/external_text_formatter.h b/src/function/external_text_formatter.h
index 4a2fb7e..23e6ab9 100644
--- a/src/function/external_text_formatter.h
+++ b/src/function/external_text_formatter.h
@@ -18,7 +18,7 @@ class FunctionExternalTextFormatter : public FunctionBase<
 	protected:
 		friend FunctionBase;
 
-		xercesc::DOMDocument* constructDocument(
+		DomDocumentCache::document_ptr constructDocument(
 			boost::filesystem::path,
 			std::string
 		);
diff --git a/src/function/read_directory.cc b/src/function/read_directory.cc
index d5357e8..ad82217 100644
--- a/src/function/read_directory.cc
+++ b/src/function/read_directory.cc
@@ -1,29 +1,21 @@
 #include "read_directory.h"
 
-#include <xercesc/dom/DOMDocument.hpp>
-#include <xercesc/dom/DOMImplementation.hpp>
-#include <xercesc/dom/DOMElement.hpp>
-
 #include "support/xerces_string_guard.h"
 #include "support/dom/result_node_facade.h"
 
 namespace InputXSLT {
 
-xercesc::DOMDocument* FunctionReadDirectory::constructDocument(
+DomDocumentCache::document_ptr FunctionReadDirectory::constructDocument(
 	boost::filesystem::path directoryPath) {
-	xercesc::DOMDocument* const domDocument(
-		xercesc::DOMImplementation::getImplementation()->createDocument(
-			nullptr,
-			*XercesStringGuard<XMLCh>("content"),
-			nullptr
-		)
+	DomDocumentCache::document_ptr domDocument(
+		DomDocumentCache::createDocument()
 	);
 
 	xercesc::DOMNode* const rootNode(
 		domDocument->getDocumentElement()
 	);
 
-	ResultNodeFacade result(domDocument, rootNode, "directory");
+	ResultNodeFacade result(domDocument.get(), rootNode, "directory");
 	result.setAttribute("path", directoryPath.string());
 
 	if ( boost::filesystem::is_directory(directoryPath) ) {
@@ -34,7 +26,7 @@ xercesc::DOMDocument* FunctionReadDirectory::constructDocument(
 		FilesystemContext::iterate(
 			directoryPath,
 			[&domDocument, &resultNode](const boost::filesystem::path& p) {
-			ResultNodeFacade result(domDocument, resultNode, "entry");
+			ResultNodeFacade result(domDocument.get(), resultNode, "entry");
 
 			switch ( boost::filesystem::status(p).type() ) {
 				case boost::filesystem::regular_file: {
diff --git a/src/function/read_directory.h b/src/function/read_directory.h
index 898132a..59ece1a 100644
--- a/src/function/read_directory.h
+++ b/src/function/read_directory.h
@@ -17,7 +17,8 @@ class FunctionReadDirectory : public FunctionBase<
 	protected:
 		friend FunctionBase;
 
-		xercesc::DOMDocument* constructDocument(boost::filesystem::path);
+		DomDocumentCache::document_ptr constructDocument(
+			boost::filesystem::path);
 
 };
 
diff --git a/src/function/read_file.cc b/src/function/read_file.cc
index f27a38e..cb1e57f 100644
--- a/src/function/read_file.cc
+++ b/src/function/read_file.cc
@@ -1,8 +1,5 @@
 #include "read_file.h"
 
-#include <xercesc/dom/DOMDocument.hpp>
-#include <xercesc/dom/DOMImplementation.hpp>
-#include <xercesc/dom/DOMElement.hpp>
 #include <xercesc/parsers/XercesDOMParser.hpp>
 #include <xercesc/framework/LocalFileInputSource.hpp>
 
@@ -62,21 +59,17 @@ boost::optional<std::string> readPlainFile(
 
 namespace InputXSLT {
 
-xercesc::DOMDocument* FunctionReadFile::constructDocument(
+DomDocumentCache::document_ptr FunctionReadFile::constructDocument(
 	boost::filesystem::path filePath) {
-	xercesc::DOMDocument* const domDocument(
-		xercesc::DOMImplementation::getImplementation()->createDocument(
-			nullptr,
-			*XercesStringGuard<XMLCh>("content"),
-			nullptr
-		)
+	DomDocumentCache::document_ptr domDocument(
+		DomDocumentCache::createDocument()
 	);
 
 	xercesc::DOMNode* const rootNode(
 		domDocument->getDocumentElement()
 	);
 
-	ResultNodeFacade result(domDocument, rootNode, "file");
+	ResultNodeFacade result(domDocument.get(), rootNode, "file");
 	result.setAttribute("path", filePath.string());
 
 	if ( boost::filesystem::is_regular_file(filePath) ) {
@@ -84,7 +77,10 @@ xercesc::DOMDocument* FunctionReadFile::constructDocument(
 			if ( isXmlFile(filePath) ) {
 				result.setAttribute("type", "xml");
 
-				if ( auto importedNode = readXmlFile(filePath, domDocument) ) {
+				if ( auto importedNode = readXmlFile(
+					filePath,
+					domDocument.get()) 
+				) {
 					result.setContent(*importedNode);
 
 					result.setAttribute("result", "success");
diff --git a/src/function/read_file.h b/src/function/read_file.h
index fdd70ac..3026c79 100644
--- a/src/function/read_file.h
+++ b/src/function/read_file.h
@@ -17,7 +17,8 @@ class FunctionReadFile : public FunctionBase<
 	protected:
 		friend FunctionBase;
 
-		xercesc::DOMDocument* constructDocument(boost::filesystem::path);
+		DomDocumentCache::document_ptr constructDocument(
+			boost::filesystem::path);
 
 };
 
diff --git a/src/function/transform.cc b/src/function/transform.cc
index e53b55f..c97897e 100644
--- a/src/function/transform.cc
+++ b/src/function/transform.cc
@@ -2,10 +2,6 @@
 
 #include <xalanc/XercesParserLiaison/FormatterToXercesDOM.hpp>
 
-#include <xercesc/dom/DOMDocument.hpp>
-#include <xercesc/dom/DOMImplementation.hpp>
-#include <xercesc/dom/DOMElement.hpp>
-
 #include "transformer_facade.h"
 #include "support/xerces_string_guard.h"
 #include "support/dom/result_node_facade.h"
@@ -30,28 +26,24 @@ inline void handleErrors(
 
 namespace InputXSLT {
 
-xercesc::DOMDocument* FunctionTransform::constructDocument(
+DomDocumentCache::document_ptr FunctionTransform::constructDocument(
 	xalan::XSLTInputSource  inputSource,
 	xalan::XSLTInputSource  transformationSource
 ) {
-	xercesc::DOMDocument* const domDocument(
-		xercesc::DOMImplementation::getImplementation()->createDocument(
-			nullptr,
-			*XercesStringGuard<XMLCh>("content"),
-			nullptr
-		)
+	DomDocumentCache::document_ptr domDocument(
+		DomDocumentCache::createDocument()
 	);
 
 	xercesc::DOMElement* const rootElement(
 		domDocument->getDocumentElement()
 	);
 
-	ResultNodeFacade result(domDocument, rootElement, "transformation");
+	ResultNodeFacade result(domDocument.get(), rootElement, "transformation");
 	TransformerFacade transformer(this->include_resolver_);
 
 	try {
 		xalan::FormatterToXercesDOM targetFormatter(
-			domDocument,
+			domDocument.get(),
 			result.getResultElement()
 		);
 
diff --git a/src/function/transform.h b/src/function/transform.h
index b8e733d..95acba3 100644
--- a/src/function/transform.h
+++ b/src/function/transform.h
@@ -18,7 +18,7 @@ class FunctionTransform : public FunctionBase<
 	protected:
 		friend FunctionBase;
 
-		xercesc::DOMDocument* constructDocument(
+		DomDocumentCache::document_ptr constructDocument(
 			xalan::XSLTInputSource,
 			xalan::XSLTInputSource
 		);
diff --git a/src/function/write_file.cc b/src/function/write_file.cc
index 024a87a..872160b 100644
--- a/src/function/write_file.cc
+++ b/src/function/write_file.cc
@@ -5,10 +5,6 @@
 #include <xalanc/XMLSupport/FormatterToXML.hpp>
 #include <xalanc/XMLSupport/FormatterTreeWalker.hpp>
 
-#include <xercesc/dom/DOMDocument.hpp>
-#include <xercesc/dom/DOMImplementation.hpp>
-#include <xercesc/dom/DOMElement.hpp>
-
 #include <boost/filesystem.hpp>
 #include <boost/filesystem/fstream.hpp>
 
@@ -34,11 +30,10 @@ bool serializeNodeToFile(
 			if ( contentType == xalan::XalanNode::TEXT_NODE ) {
 				file << InputXSLT::toString(contentNode->getNodeValue());
 			} else {
-				xalan::XalanStdOutputStream outputStream(file);
+				xalan::XalanStdOutputStream         outputStream(file);
 				xalan::XalanOutputStreamPrintWriter outputWriter(outputStream);
-
-				xalan::FormatterToXML formatter(outputWriter);
-				xalan::FormatterTreeWalker walker(formatter);
+				xalan::FormatterToXML               formatter(outputWriter);
+				xalan::FormatterTreeWalker          walker(formatter);
 
 				formatter.startDocument();
 
@@ -62,23 +57,19 @@ bool serializeNodeToFile(
 
 namespace InputXSLT {
 
-xercesc::DOMDocument* FunctionWriteFile::constructDocument(
+DomDocumentCache::document_ptr FunctionWriteFile::constructDocument(
 	boost::filesystem::path filePath,
 	xalan::XalanNode* const contentNode
 ) {
-	xercesc::DOMDocument* const domDocument(
-		xercesc::DOMImplementation::getImplementation()->createDocument(
-			nullptr,
-			*XercesStringGuard<XMLCh>("content"),
-			nullptr
-		)
+	DomDocumentCache::document_ptr domDocument(
+		DomDocumentCache::createDocument()
 	);
 
 	xercesc::DOMNode* const rootNode(
 		domDocument->getDocumentElement()
 	);
 
-	ResultNodeFacade result(domDocument, rootNode, "file");
+	ResultNodeFacade result(domDocument.get(), rootNode, "file");
 	result.setAttribute("path", filePath.string());
 
 	if ( contentNode != nullptr ) {
diff --git a/src/function/write_file.h b/src/function/write_file.h
index 5fd9f3e..c1d6100 100644
--- a/src/function/write_file.h
+++ b/src/function/write_file.h
@@ -16,7 +16,7 @@ class FunctionWriteFile : public FunctionBase<
 	protected:
 		friend FunctionBase;
 
-		xercesc::DOMDocument* constructDocument(
+		DomDocumentCache::document_ptr constructDocument(
 			boost::filesystem::path,
 			xalan::XalanNode* const
 		);
diff --git a/src/support/dom/document_cache.cc b/src/support/dom/document_cache.cc
index 0ad540c..23805b5 100644
--- a/src/support/dom/document_cache.cc
+++ b/src/support/dom/document_cache.cc
@@ -1,19 +1,43 @@
 #include "document_cache.h"
 
+#include <xercesc/dom/DOMDocument.hpp>
+#include <xercesc/dom/DOMImplementation.hpp>
+
 #include <stdexcept>
 
+#include "support/xerces_string_guard.h"
+
 namespace InputXSLT {
 
+auto DomDocumentCache::createDocument() -> document_ptr {
+	return document_ptr(
+		xercesc::DOMImplementation::getImplementation()->createDocument(
+			nullptr,
+			*XercesStringGuard<XMLCh>("content"),
+			nullptr
+		)
+	);
+}
+
 DomDocumentCache::DomDocumentCache():
 	write_mutex_(),
 	cache_() { }
 
-xalan::XalanDocument* DomDocumentCache::create(xercesc::DOMDocument* document) {
+xalan::XalanDocument* DomDocumentCache::create(document_ptr&& document) {
 	std::lock_guard<std::mutex> guard(this->write_mutex_);
 
-	this->cache_.emplace(new item(document));
+	this->cache_.emplace(
+		new item(
+			std::move(document)
+		)
+	);
 
 	return this->cache_.top()->getXalanDocument();
 }
 
+void DomDocumentCache::document_deleter::operator()(
+	xercesc::DOMDocument* document) {
+	document->release();
+}
+
 }
diff --git a/src/support/dom/document_cache.h b/src/support/dom/document_cache.h
index 1f9a9e3..3aeb332 100644
--- a/src/support/dom/document_cache.h
+++ b/src/support/dom/document_cache.h
@@ -14,10 +14,23 @@
 namespace InputXSLT {
 
 class DomDocumentCache {
+	class document_deleter {
+		friend std::unique_ptr<xercesc::DOMDocument, document_deleter>;
+
+		void operator()(xercesc::DOMDocument*);
+	};
+
 	public:
+		typedef std::unique_ptr<
+			xercesc::DOMDocument,
+			document_deleter
+		> document_ptr;
+
+		static document_ptr createDocument();
+
 		DomDocumentCache();
 
-		xalan::XalanDocument* create(xercesc::DOMDocument*);
+		xalan::XalanDocument* create(document_ptr&&);
 
 	private:
 		class item;
diff --git a/src/support/dom/document_cache_item.cc b/src/support/dom/document_cache_item.cc
index 9798bfa..a684d97 100644
--- a/src/support/dom/document_cache_item.cc
+++ b/src/support/dom/document_cache_item.cc
@@ -2,20 +2,16 @@
 
 namespace InputXSLT {
 
-DomDocumentCache::item::item(xercesc::DOMDocument* document):
+DomDocumentCache::item::item(document_ptr&& document):
+	document_(std::move(document)),
 	parser_(),
 	dom_support_(parser_),
-	document_(document),
 	parsed_source_(
-		document_,
+		document_.get(),
 		parser_,
 		dom_support_
 	) { }
 
-DomDocumentCache::item::~item() {
-	this->document_->release();
-}
-
 xalan::XalanDocument* DomDocumentCache::item::getXalanDocument() {
 	return this->parsed_source_.getDocument();
 }
diff --git a/src/support/dom/document_cache_item.h b/src/support/dom/document_cache_item.h
index 13fddfc..ebc9172 100644
--- a/src/support/dom/document_cache_item.h
+++ b/src/support/dom/document_cache_item.h
@@ -14,19 +14,17 @@ namespace InputXSLT {
 
 class DomDocumentCache::item {
 	public:
-		~item();
-
 		xalan::XalanDocument* getXalanDocument();
 
 	protected:
 		friend DomDocumentCache;
 
-		item(xercesc::DOMDocument*);
+		item(document_ptr&&);
 
 	private:
+		document_ptr document_;
 		xalan::XercesParserLiaison parser_;
 		xalan::XercesDOMSupport dom_support_;
-		xercesc::DOMDocument* const document_;
 		xalan::XercesDOMWrapperParsedSource parsed_source_;
 
 };
diff --git a/src/transformer_facade.cc b/src/transformer_facade.cc
index 10c8c7a..76b68d6 100644
--- a/src/transformer_facade.cc
+++ b/src/transformer_facade.cc
@@ -11,10 +11,8 @@
 #include <xalanc/XercesParserLiaison/XercesDOMSupport.hpp>
 #include <xalanc/XalanTransformer/XercesDOMWrapperParsedSource.hpp>
 
-#include <xercesc/dom/DOMDocument.hpp>
-#include <xercesc/dom/DOMImplementation.hpp>
-
 #include "support/xerces_string_guard.h"
+#include "support/dom/document_cache.h"
 
 namespace InputXSLT {
 
@@ -59,19 +57,15 @@ void TransformerFacade::generate(
 ) {
 	ErrorCapacitor errorCapacitor(&this->error_multiplexer_);
 
-	xercesc::DOMDocument* const inputDocument(
-		xercesc::DOMImplementation::getImplementation()->createDocument(
-			nullptr,
-			*XercesStringGuard<XMLCh>("dummy"),
-			nullptr
-		)
+	DomDocumentCache::document_ptr inputDocument(
+		DomDocumentCache::createDocument()
 	);
 
 	xalan::XercesParserLiaison parserLiaison;
 	xalan::XercesDOMSupport domSupport(parserLiaison);
 
 	xalan::XercesDOMWrapperParsedSource inputParsedSource(
-		inputDocument,
+		inputDocument.get(),
 		parserLiaison,
 		domSupport
 	);
@@ -82,8 +76,6 @@ void TransformerFacade::generate(
 		target
 	);
 
-	inputDocument->release();
-
 	errorCapacitor.discharge();
 }
 
@@ -94,12 +86,12 @@ void TransformerFacade::generate(
 ) {
 	ErrorCapacitor errorCapacitor(&this->error_multiplexer_);
 
-	xercesc::DOMDocument* const inputDocument(
-		xercesc::DOMImplementation::getImplementation()->createDocument()
+	DomDocumentCache::document_ptr inputDocument(
+		DomDocumentCache::createDocument()
 	);
 
 	xalan::FormatterToXercesDOM inputFormatter(
-		inputDocument,
+		inputDocument.get(),
 		inputDocument->getDocumentElement()
 	);
 
@@ -121,8 +113,6 @@ void TransformerFacade::generate(
 		target
 	);
 
-	inputDocument->release();
-
 	errorCapacitor.discharge();
 }
 
-- 
cgit v1.2.3