Add parametrized messaging and serialization to exceptions.
[shibboleth/cpp-xmltooling.git] / xmltooling / exceptions.h
index f527350..39ee359 100644 (file)
 #if !defined(__xmltooling_exceptions_h__)\r
 #define __xmltooling_exceptions_h__\r
 \r
+#include <map>\r
 #include <string>\r
+#include <vector>\r
+#include <iostream>\r
 #include <xmltooling/base.h>\r
 \r
-#define DECL_XMLTOOLING_EXCEPTION(type) \\r
-    class XMLTOOL_EXCEPTIONAPI(XMLTOOL_API) type : public XMLToolingException { \\r
+/**\r
+ * Declares a derived exception class\r
+ * \r
+ * @param name  the exception class\r
+ * @param base  the base class\r
+ */\r
+#define DECL_XMLTOOLING_EXCEPTION(name,base) \\r
+    class XMLTOOL_EXCEPTIONAPI(XMLTOOL_API) name : public xmltooling::base { \\r
     public: \\r
-        type(const char* const msg) : XMLToolingException(msg) {} \\r
-        type(const std::string& msg) : XMLToolingException(msg) {} \\r
-        virtual ~type() {} \\r
+        name(const char* msg=NULL, const xmltooling::params& p=xmltooling::params()) \\r
+            : xmltooling::base(msg,p) {} \\r
+        name(const char* msg, const xmltooling::namedparams& p) \\r
+            : xmltooling::base(msg,p) {} \\r
+        name(const std::string& msg, const xmltooling::params& p=xmltooling::params()) \\r
+            : xmltooling::base(msg,p) {} \\r
+        name(const std::string& msg, const xmltooling::namedparams& p) \\r
+            : xmltooling::base(msg,p) {} \\r
+        virtual ~name() {} \\r
+        virtual const char* getClassName() const { return "xmltooling::"#name; } \\r
+        void raise() const {throw *this;} \\r
+    }\r
+\r
+/**\r
+ * Declares a factory function for an exception class.\r
+ * \r
+ * @param name  the exception class name\r
+ */\r
+#define DECL_EXCEPTION_FACTORY(name) \\r
+    xmltooling::XMLToolingException* name##Factory() \\r
+    { \\r
+        return new xmltooling::name(); \\r
     }\r
 \r
+/**\r
+ * Registers a factory for an exception class.\r
+ * \r
+ * @param name  the exception class name\r
+ */\r
+#define REGISTER_EXCEPTION_FACTORY(name) XMLToolingException::registerFactory("xmltooling::"#name,name##Factory)\r
+\r
 namespace xmltooling {\r
     \r
     /**\r
-     * Base exception class.\r
-     * std::exception seems to be inconsistently defined, so this is just\r
-     * a substitute base class.\r
+     * Wrapper around a variable number of arguments.\r
      */\r
+    class XMLTOOL_API params\r
+    {\r
+    public:\r
+        /**\r
+         * Initializes with zero parameters.\r
+         */\r
+        params() {}\r
+        \r
+        /**\r
+         * Initializes the parameter set.\r
+         * \r
+         * @param count     the number of parameters that follow\r
+         */\r
+        params(int count,...);\r
+        \r
+        /**\r
+         * Returns an immutable reference to the set of parameters.\r
+         * \r
+         * @return the parameter set\r
+         */\r
+        const std::vector<const char*>& get() const {return v;}\r
+        \r
+    protected:\r
+        std::vector<const char*> v;\r
+    };\r
+    \r
+    /**\r
+     * Wrapper around a variable number of name/value pairs.\r
+     */\r
+    class XMLTOOL_API namedparams : public params\r
+    {\r
+    public:\r
+        /**\r
+         * Initializes with zero parameters.\r
+         */\r
+        namedparams() {}\r
+\r
+        /**\r
+         * Initializes the named parameter set.\r
+         * \r
+         * @param count     the number of name/value pairs that follow (must be even)\r
+         */\r
+        namedparams(int count,...);\r
+    };\r
+\r
+    /**\r
+     * Base exception class, supports parametrized messages and XML serialization.\r
+     * Parameters are prefixed with a dollar sign ($) and can be positional ($1)\r
+     * or named ($info).\r
+     */\r
+    class XMLTOOL_EXCEPTIONAPI(XMLTOOL_API) XMLToolingException;\r
+    typedef XMLToolingException* ExceptionFactory();\r
+    \r
     class XMLTOOL_EXCEPTIONAPI(XMLTOOL_API) XMLToolingException\r
     {\r
     public:\r
-        XMLToolingException() {}\r
         virtual ~XMLToolingException() {}\r
-        XMLToolingException(const char* const msg) : m_msg(msg) {}\r
-        XMLToolingException(const std::string& msg) : m_msg(msg) {}\r
-        virtual const char* what() const { return m_msg.c_str(); }\r
+\r
+        /**\r
+         * Constructs an exception using a message and positional parameters.\r
+         * \r
+         * @param msg   error message\r
+         * @param p     an ordered set of positional parameter strings\r
+         */\r
+        XMLToolingException(const char* msg=NULL, const params& p=params());\r
+\r
+        /**\r
+         * Constructs an exception using a message and named parameters.\r
+         * \r
+         * @param msg   error message\r
+         * @param p     a set of named parameter strings\r
+         */\r
+        XMLToolingException(const char* msg, const namedparams& p);\r
+\r
+        /**\r
+         * Constructs an exception using a message and positional parameters.\r
+         * \r
+         * @param msg   error message\r
+         * @param p     an ordered set of positional parameter strings\r
+         */\r
+        XMLToolingException(const std::string& msg, const params& p=params());\r
+\r
+        /**\r
+         * Constructs an exception using a message and named parameters.\r
+         * \r
+         * @param msg   error message\r
+         * @param p     a set of named parameter strings\r
+         */\r
+        XMLToolingException(const std::string& msg, const namedparams& p);\r
+\r
+        /**\r
+         * Returns the error message, after processing any parameter references.\r
+         * \r
+         * @return  the processed message\r
+         */\r
+        const char* getMessage() const;\r
+\r
+        /**\r
+         * Returns the error message, after processing any parameter references.\r
+         * \r
+         * @return  the processed message\r
+         */\r
+        const char* what() const {return getMessage();}\r
+\r
+        /**\r
+         * Sets the error message.\r
+         * \r
+         * @param msg   the error message\r
+         */\r
+        void setMessage(const char* msg);\r
+\r
+        /**\r
+         * Sets the error message.\r
+         * \r
+         * @param msg   the error message\r
+         */\r
+        void setMessage(const std::string& msg) {\r
+            setMessage(msg.c_str());\r
+        }\r
+\r
+        /**\r
+         * Attach a set of positional parameters to the exception.\r
+         * \r
+         * @param p     an ordered set of named parameter strings\r
+         */\r
+        void addProperties(const params& p);\r
+        \r
+        /**\r
+         * Attach a set of named parameters to the exception.\r
+         * \r
+         * @param p     a set of named parameter strings\r
+         */\r
+        void addProperties(const namedparams& p);\r
+\r
+        /**\r
+         * Attach a single positional parameter at the next available position.\r
+         * \r
+         * @param value the parameter value\r
+         */\r
+        void addProperty(const char* value) {\r
+            addProperties(params(1,value));\r
+        }\r
+\r
+        /**\r
+         * Attach a single named parameter.\r
+         * \r
+         * @param name  the parameter name\r
+         * @param value the parameter value\r
+         */\r
+        void addProperty(const char* name, const char* value) {\r
+            addProperties(namedparams(1,name,value));\r
+        }\r
+\r
+        /**\r
+         * Returns the parameter property with the designated position (based from one).\r
+         * \r
+         * @param index     position to access\r
+         * @return  the parameter property or NULL\r
+         */\r
+        const char* getProperty(unsigned int index) const;\r
+\r
+        /**\r
+         * Returns the parameter property with the designated name.\r
+         * \r
+         * @param name     named parameter to access\r
+         * @return  the parameter property or NULL\r
+         */\r
+        const char* getProperty(const char* name) const;\r
+\r
+        /**\r
+         * Raises an exception using itself.\r
+         * Used to raise an exception of a derived type.\r
+         */\r
+        virtual void raise() const {\r
+            throw *this;\r
+        }\r
+\r
+        /**\r
+         * Returns a unique name for the exception class.\r
+         * \r
+         * @return class name\r
+         */\r
+        virtual const char* getClassName() const {\r
+            return "xmltooling::XMLToolingException";\r
+        }\r
+        \r
+        /**\r
+         * Returns a string containing a serialized representation of the exception.\r
+         * \r
+         * @return  the serialization\r
+         */\r
+        std::string toString() const;\r
+\r
     private:\r
         std::string m_msg;\r
+        mutable std::string m_processedmsg;\r
+        std::map<std::string,std::string> m_params;\r
+\r
+    public:\r
+        /**\r
+         * Builds an empty exception of the given type.\r
+         * \r
+         * @param exceptionClass    the name of the exception type to build\r
+         * @return an empty exception object\r
+         */\r
+        static XMLToolingException* getInstance(const char* exceptionClass);\r
+\r
+        /**\r
+         * Builds an exception from a serialized input stream.\r
+         * \r
+         * @param in    input stream\r
+         * @return the exception object found in the stream\r
+         */\r
+        static XMLToolingException* fromStream(std::istream& in);\r
+        \r
+        /**\r
+         * Builds an exception from a serialized input buffer.\r
+         * \r
+         * @param s   input buffer\r
+         * @return the exception object found in the buffer\r
+         */\r
+        static XMLToolingException* fromString(const char* s);\r
+                \r
+        /**\r
+         * Registers a factory to create exceptions of a given class name.\r
+         * \r
+         * @param exceptionClass    name of exception type\r
+         * @param factory           factory function to build exceptions with\r
+         */\r
+        static void registerFactory(const char* exceptionClass, ExceptionFactory* factory) {\r
+            m_factoryMap[exceptionClass] = factory;\r
+        }\r
+        \r
+        /**\r
+         * Unregisters the factory for a given class name.\r
+         * \r
+         * @param exceptionClass    name of exception type\r
+         */\r
+        static void deregisterFactory(const char* exceptionClass) {\r
+            m_factoryMap.erase(exceptionClass);\r
+        }\r
+\r
+    private:\r
+        typedef std::map<std::string,ExceptionFactory*> ExceptionFactoryMap;\r
+        static ExceptionFactoryMap m_factoryMap;\r
     };\r
 \r
-    DECL_XMLTOOLING_EXCEPTION(XMLParserException);\r
-    DECL_XMLTOOLING_EXCEPTION(XMLObjectException);\r
-    DECL_XMLTOOLING_EXCEPTION(MarshallingException);\r
-    DECL_XMLTOOLING_EXCEPTION(UnmarshallingException);\r
-    DECL_XMLTOOLING_EXCEPTION(UnknownElementException);\r
-    DECL_XMLTOOLING_EXCEPTION(UnknownAttributeException);\r
-    DECL_XMLTOOLING_EXCEPTION(ValidationException);\r
-    DECL_XMLTOOLING_EXCEPTION(SignatureException);\r
+    DECL_XMLTOOLING_EXCEPTION(XMLParserException,XMLToolingException);\r
+    DECL_XMLTOOLING_EXCEPTION(XMLObjectException,XMLToolingException);\r
+    DECL_XMLTOOLING_EXCEPTION(MarshallingException,XMLToolingException);\r
+    DECL_XMLTOOLING_EXCEPTION(UnmarshallingException,XMLToolingException);\r
+    DECL_XMLTOOLING_EXCEPTION(UnknownElementException,XMLToolingException);\r
+    DECL_XMLTOOLING_EXCEPTION(UnknownAttributeException,XMLToolingException);\r
+    DECL_XMLTOOLING_EXCEPTION(ValidationException,XMLToolingException);\r
+    DECL_XMLTOOLING_EXCEPTION(SignatureException,XMLToolingException);\r
 \r
 };\r
 \r