From f6ff54c492df81018cf48da039ee681508f88e46 Mon Sep 17 00:00:00 2001 From: Adrian Kummerlaender Date: Sat, 16 Aug 2014 23:30:36 +0200 Subject: Implemented primitive optional parameter support for external functions * renamed FunctionExternalTextFormatter into FunctionExternalCommand ** the goal is to provide a general interface to a variety of external commands *** e.g. not just text formatters but system utilities for file management and so on ** this requires the stdin parameter to be optional as not all external commands require stdin input * implemented "filter_derived" helper template to determine amount of optional parameters ** optional parameters are defined as "boost::optional" specializations *** they in turn can be detected by checking if "boost::optional_detail::optional_tag" is a base class * "callConstructDocument" member method of "FunctionBase" performs additional bounds checking of parameter vector * "boost::optional" specific member overload was added to "XObjectValue" helper class ** we will have to provide full specializations for all optional types as C++ prohibits partial member function template specialization * renamed the external function in "PlattformGuard" * changed README.md and test cases accordingly --- src/function/base.h | 27 +++++++-- src/function/external_command.cc | 99 +++++++++++++++++++++++++++++++ src/function/external_command.h | 31 ++++++++++ src/function/external_text_formatter.cc | 101 -------------------------------- src/function/external_text_formatter.h | 30 ---------- src/platform_guard.cc | 6 +- src/support/filesystem_context.h | 2 +- src/support/include_entity_resolver.cc | 2 +- src/support/include_entity_resolver.h | 2 +- src/support/type/filter.h | 24 ++++++++ src/support/type/xobject_value.cc | 13 +++- 11 files changed, 193 insertions(+), 144 deletions(-) create mode 100644 src/function/external_command.cc create mode 100644 src/function/external_command.h delete mode 100644 src/function/external_text_formatter.cc delete mode 100644 src/function/external_text_formatter.h create mode 100644 src/support/type/filter.h (limited to 'src') diff --git a/src/function/base.h b/src/function/base.h index 2d1e4c4..a8f93b9 100644 --- a/src/function/base.h +++ b/src/function/base.h @@ -5,6 +5,8 @@ #include #include +#include + #include #include @@ -14,6 +16,7 @@ #include "support/include_entity_resolver.h" #include "support/dom/document_cache.h" #include "support/type/sequence.h" +#include "support/type/filter.h" #include "support/type/xobject_value.h" namespace InputXSLT { @@ -23,7 +26,13 @@ template < typename... Types > class FunctionBase : public xalan::Function { - static const std::size_t parameter_count = sizeof...(Types); + static const std::size_t parameter_count = sizeof...(Types); + static const std::size_t optional_parameter_count = std::tuple_size< + typename filter_derived< + boost::optional_detail::optional_tag, + Types... + >::type + >::value; public: FunctionBase(IncludeEntityResolver* resolver): @@ -108,16 +117,20 @@ class FunctionBase : public xalan::Function { valueGetter.get - >::type>(parameters[Index])... + >::type>( + Index < parameters.size() + ? parameters[Index] + : xalan::XObjectPtr() + )... ) ); } inline void validateParameters( - const XObjectArgVectorType& parameters, + const XObjectArgVectorType& parameters, xalan::XPathExecutionContext& executionContext, - xalan::XalanNode* context, - const xalan::Locator* locator + xalan::XalanNode* context, + const xalan::Locator* locator ) const { const bool anyNull = std::any_of( parameters.begin(), @@ -127,7 +140,9 @@ class FunctionBase : public xalan::Function { } ); - if ( parameters.size() != parameter_count || anyNull ) { + if ( parameters.size() > parameter_count || + parameters.size() < optional_parameter_count || + anyNull ) { xalan::XPathExecutionContext::GetAndReleaseCachedString guard( executionContext ); diff --git a/src/function/external_command.cc b/src/function/external_command.cc new file mode 100644 index 0000000..bd2bf84 --- /dev/null +++ b/src/function/external_command.cc @@ -0,0 +1,99 @@ +#include "external_command.h" + +#include + +#include + +#include + +#include + +#include "support/xerces_string_guard.h" +#include "support/dom/result_node_facade.h" + +namespace { + +using InputXSLT::XercesStringGuard; + +inline xercesc::DOMNode* importDocumentElement( + boost::process::pistream& outputStream, + xercesc::DOMDocument* const domDocument +) { + std::stringstream xmlStream( + "" + std::string( + (std::istreambuf_iterator(outputStream)), + (std::istreambuf_iterator()) + ) + "" + ); + + xercesc::XercesDOMParser parser; + parser.parse(xalan::XSLTInputSource(xmlStream)); + + return domDocument->importNode( + parser.getDocument()->getDocumentElement(), + true + ); +} + +} + +namespace InputXSLT { + +DomDocumentCache::document_ptr FunctionExternalCommand::constructDocument( + std::string command, + boost::optional stdinText +) const { + DomDocumentCache::document_ptr domDocument( + DomDocumentCache::createDocument("content") + ); + + boost::process::context context; + context.environment = boost::process::self::get_environment(); + context.stdout_behavior = boost::process::capture_stream(); + context.stdin_behavior = boost::process::capture_stream(); + + boost::process::child commandProcess( + boost::process::launch_shell(command, context) + ); + + if ( stdinText ) { + boost::process::postream& inputStream = commandProcess.get_stdin(); + inputStream << *stdinText; + inputStream.close(); + } + + boost::process::pistream& outputStream = commandProcess.get_stdout(); + boost::process::status status = commandProcess.wait(); + + ResultNodeFacade result(domDocument.get(), "output"); + result.setAttribute("command", command); + result.setAttribute("code", std::to_string(status.exit_status())); + + if ( status.exited() ) { + try { + result.setContent( + importDocumentElement( + outputStream, + domDocument.get() + )->getChildNodes() + ); + + result.setAttribute("result", "success"); + } + catch ( const xercesc::DOMException& exception ) { + result.setAttribute("result", "error"); + + result.setValueNode( + "error", + *XercesStringGuard(exception.msg) + ); + } + } else { + result.setAttribute("result", "error"); + } + + + return domDocument; +} + +} diff --git a/src/function/external_command.h b/src/function/external_command.h new file mode 100644 index 0000000..8af5079 --- /dev/null +++ b/src/function/external_command.h @@ -0,0 +1,31 @@ +#ifndef INPUTXSLT_SRC_FUNCTION_EXTERNAL_COMMAND_H_ +#define INPUTXSLT_SRC_FUNCTION_EXTERNAL_COMMAND_H_ + +#include +#include + +#include "base.h" + +namespace InputXSLT { + +class FunctionExternalCommand : public FunctionBase< + FunctionExternalCommand, + std::string, + boost::optional +> { + public: + using FunctionBase::FunctionBase; + + protected: + friend FunctionBase; + + DomDocumentCache::document_ptr constructDocument( + std::string, + boost::optional + ) const; + +}; + +} + +#endif // INPUTXSLT_SRC_FUNCTION_EXTERNAL_COMMAND_H_ diff --git a/src/function/external_text_formatter.cc b/src/function/external_text_formatter.cc deleted file mode 100644 index 03902e9..0000000 --- a/src/function/external_text_formatter.cc +++ /dev/null @@ -1,101 +0,0 @@ -#include "external_text_formatter.h" - -#include - -#include - -#include - -#include - -#include "support/xerces_string_guard.h" -#include "support/dom/result_node_facade.h" - -namespace { - -using InputXSLT::XercesStringGuard; - -inline xercesc::DOMNode* importDocumentElement( - boost::process::pistream& outputStream, - xercesc::DOMDocument* const domDocument -) { - std::stringstream xmlStream( - "" + std::string( - (std::istreambuf_iterator(outputStream)), - (std::istreambuf_iterator()) - ) + "" - ); - - xercesc::XercesDOMParser parser; - parser.parse(xalan::XSLTInputSource(xmlStream)); - - return domDocument->importNode( - parser.getDocument()->getDocumentElement(), - true - ); -} - -} - -namespace InputXSLT { - -DomDocumentCache::document_ptr FunctionExternalTextFormatter::constructDocument( - std::string formatterCommand, - std::string stdinText -) const { - DomDocumentCache::document_ptr domDocument( - DomDocumentCache::createDocument("content") - ); - - boost::process::context context; - context.environment = boost::process::self::get_environment(); - context.stdout_behavior = boost::process::capture_stream(); - context.stdin_behavior = boost::process::capture_stream(); - - boost::process::child formatterProcess( - boost::process::launch_shell( - formatterCommand, - context - ) - ); - - boost::process::postream& inputStream = formatterProcess.get_stdin(); - boost::process::pistream& outputStream = formatterProcess.get_stdout(); - - inputStream << stdinText; - inputStream.close(); - - boost::process::status status = formatterProcess.wait(); - - ResultNodeFacade result(domDocument.get(), "output"); - result.setAttribute("formatter", formatterCommand); - result.setAttribute("code", std::to_string(status.exit_status())); - - if ( status.exited() ) { - try { - result.setContent( - importDocumentElement( - outputStream, - domDocument.get() - )->getChildNodes() - ); - - result.setAttribute("result", "success"); - } - catch ( const xercesc::DOMException& exception ) { - result.setAttribute("result", "error"); - - result.setValueNode( - "error", - *XercesStringGuard(exception.msg) - ); - } - } else { - result.setAttribute("result", "error"); - } - - - return domDocument; -} - -} diff --git a/src/function/external_text_formatter.h b/src/function/external_text_formatter.h deleted file mode 100644 index 4788784..0000000 --- a/src/function/external_text_formatter.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef INPUTXSLT_SRC_FUNCTION_EXTERNAL_TEXT_FORMATTER_H_ -#define INPUTXSLT_SRC_FUNCTION_EXTERNAL_TEXT_FORMATTER_H_ - -#include - -#include "base.h" - -namespace InputXSLT { - -class FunctionExternalTextFormatter : public FunctionBase< - FunctionExternalTextFormatter, - std::string, - std::string -> { - public: - using FunctionBase::FunctionBase; - - protected: - friend FunctionBase; - - DomDocumentCache::document_ptr constructDocument( - std::string, - std::string - ) const; - -}; - -} - -#endif // INPUTXSLT_SRC_FUNCTION_EXTERNAL_TEXT_FORMATTER_H_ diff --git a/src/platform_guard.cc b/src/platform_guard.cc index 6be5b4a..f50d976 100644 --- a/src/platform_guard.cc +++ b/src/platform_guard.cc @@ -11,7 +11,7 @@ #include "function/read_directory.h" #include "function/transform.h" #include "function/generate.h" -#include "function/external_text_formatter.h" +#include "function/external_command.h" namespace InputXSLT { @@ -56,8 +56,8 @@ PlatformGuard::PlatformGuard(const std::vector& path): xalan::XalanTransformer::installExternalFunctionGlobal( customNamespace, - xalan::XalanDOMString("external-text-formatter"), - InputXSLT::FunctionExternalTextFormatter(&this->include_resolver_) + xalan::XalanDOMString("external-command"), + InputXSLT::FunctionExternalCommand(&this->include_resolver_) ); } diff --git a/src/support/filesystem_context.h b/src/support/filesystem_context.h index f3875a3..c00fe29 100644 --- a/src/support/filesystem_context.h +++ b/src/support/filesystem_context.h @@ -4,7 +4,7 @@ #include #include -#include "boost/filesystem.hpp" +#include #include #include diff --git a/src/support/include_entity_resolver.cc b/src/support/include_entity_resolver.cc index deac1d5..197b217 100644 --- a/src/support/include_entity_resolver.cc +++ b/src/support/include_entity_resolver.cc @@ -2,7 +2,7 @@ #include -#include "boost/filesystem.hpp" +#include #include "support/xalan_string.h" #include "support/xerces_string_guard.h" diff --git a/src/support/include_entity_resolver.h b/src/support/include_entity_resolver.h index ea5fb7a..e7c5542 100644 --- a/src/support/include_entity_resolver.h +++ b/src/support/include_entity_resolver.h @@ -4,7 +4,7 @@ #include #include -#include "boost/optional.hpp" +#include #include #include diff --git a/src/support/type/filter.h b/src/support/type/filter.h new file mode 100644 index 0000000..4a0e19f --- /dev/null +++ b/src/support/type/filter.h @@ -0,0 +1,24 @@ +#ifndef INPUTXSLT_SRC_SUPPORT_TYPE_FILTER_H_ +#define INPUTXSLT_SRC_SUPPORT_TYPE_FILTER_H_ + +#include +#include + +namespace InputXSLT { + +template < + typename BaseReference, + typename Head, + typename... Tail +> +struct filter_derived { + typedef typename std::conditional< + std::is_base_of::value, + std::tuple, + std::tuple + >::type type; +}; + +} + +#endif // INPUTXSLT_SRC_SUPPORT_TYPE_FILTER_H_ diff --git a/src/support/type/xobject_value.cc b/src/support/type/xobject_value.cc index 9bb6648..e457a69 100644 --- a/src/support/type/xobject_value.cc +++ b/src/support/type/xobject_value.cc @@ -4,7 +4,8 @@ #include #include -#include "boost/filesystem.hpp" +#include +#include #include @@ -26,6 +27,16 @@ std::string XObjectValue::get( return boost::trim_copy(toString(ptr->str())); } +template <> +boost::optional XObjectValue::get>( + const xalan::XObjectPtr& ptr) const { + if ( ptr.null() ) { + return boost::optional(); + } else { + return this->get(ptr); + } +} + template <> boost::filesystem::path XObjectValue::get( const xalan::XObjectPtr& ptr) const { -- cgit v1.2.3