1 /*------------------------------------------------------------------------------
  2 Name:      XmlBlasterException.cpp
  3 Project:   xmlBlaster.org
  4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
  5 Comment:   Basic xmlBlaster exception.
  6 ------------------------------------------------------------------------------*/
  7 #include <util/XmlBlasterException.h>
  8 #include <util/ErrorCode.h>
  9 #include <stdexcept>
 10 #include <util/lexical_cast.h>
 11 #include <util/Global.h>
 12 
 13 
 14 using namespace std;
 15 
 16 namespace org { namespace xmlBlaster { namespace util {
 17 
 18 XmlBlasterException::XmlBlasterException(const string &errorCodeStr,
 19                     const string &node,
 20                     const string &location,
 21                     const string &lang,
 22                     const string &message,
 23                     const string &versionInfo,
 24                     const string &timestampStr,
 25                     const string &stackTrace,
 26                     const string &embeddedMessage,
 27                     const string &transactionInfo)
 28    :                errorCodeStr_(errorCodeStr),
 29                     node_(node),
 30                     location_(location),
 31                     lang_(lang),
 32                     message_(message),
 33                     versionInfo_(versionInfo),
 34                     timestamp_(timestampStr),
 35                     stackTrace_(stackTrace),
 36                     embeddedMessage_(embeddedMessage),
 37                     transactionInfo_(transactionInfo)
 38 {
 39    if (embeddedMessage_ == "") {
 40       embeddedMessage_ = "Original errorCode=" + errorCodeStr_;
 41    }
 42    if (stackTrace_.size() < 1 && isInternal()) stackTrace_ = getStackTrace();
 43 }
 44 
 45 
 46 XmlBlasterException::XmlBlasterException(const ErrorCode &errorCode,
 47                     const string &node,
 48                     const string &location,
 49                     const string &lang,
 50                     const string &versionInfo,
 51                     const string &timestampStr,
 52                     const string &stackTrace,
 53                     const string &embeddedMessage,
 54                     const string &transactionInfo)
 55    :                errorCodeStr_(errorCode.errorCode),
 56                     node_(node),
 57                     location_(location),
 58                     lang_(lang),
 59                     message_(errorCode.description),
 60                     versionInfo_(versionInfo),
 61                     timestamp_(timestampStr),
 62                     stackTrace_(stackTrace),
 63                     embeddedMessage_(embeddedMessage),
 64                     transactionInfo_(transactionInfo)
 65 {
 66    if (embeddedMessage_ == "") {
 67       embeddedMessage_ = "Original errorCode=" + errorCodeStr_;
 68    }
 69    if (stackTrace_.size() < 1 && isInternal()) stackTrace_ = getStackTrace();
 70 }
 71 
 72 
 73 XmlBlasterException::XmlBlasterException(const ErrorCode &errorCode,
 74                     const string &node,
 75                     const string &embeddedMessage)
 76    :                errorCodeStr_(errorCode.errorCode),
 77                     node_(node),
 78                     location_(""),
 79                     lang_("en"),
 80                     message_(errorCode.description),
 81                     versionInfo_(Global::getReleaseId()),
 82                     timestamp_(""),
 83                     stackTrace_(""),
 84                     embeddedMessage_(embeddedMessage),
 85                     transactionInfo_("<transactioninfo/>")
 86 {
 87    if (embeddedMessage_ == "") {
 88       embeddedMessage_ = "Original errorCode=" + errorCodeStr_;
 89    }
 90    if (stackTrace_.size() < 1 && isInternal()) stackTrace_ = getStackTrace();
 91 }
 92 
 93 XmlBlasterException::~XmlBlasterException() throw()
 94 {
 95 }
 96 
 97 const char *XmlBlasterException::what() const throw()
 98 {
 99    str_ = toString();
100    return str_.c_str();
101 }
102 
103 string XmlBlasterException::getErrorCodeStr() const
104 {
105    return errorCodeStr_;
106 }
107 
108 string XmlBlasterException::getNode() const
109 {
110    return node_;
111 }
112 
113 string XmlBlasterException::getLocation() const
114 {
115    return location_;
116 }
117 
118 string XmlBlasterException::getLang() const
119 {
120    return lang_;
121 }
122 
123 string XmlBlasterException::getMessage() const
124 {
125    string ret = errorCodeStr_ ;
126    ret += ", node=" + node_;
127    if (getLocation() != "")        ret += ", location=" + getLocation();
128    if (getLang() != "en")          ret += ", lang=" + getLang();
129    if (getVersionInfo() != "")     ret += ", versionInfo=" + getVersionInfo();
130    if (timestamp_ != "")           ret += ", timestamp=" + getTimestamp();
131    if (getStackTrace() != "")      ret += ", stackTrace=" + getStackTrace();
132    if (getEmbeddedMessage() != "") ret += ", embeddedMessage=" + getEmbeddedMessage();
133    if (getTransactionInfo() != "" && getTransactionInfo() !=  "<transactioninfo/>")
134                                    ret += ", transactionInfo=" + getTransactionInfo();
135    ret += ", original message=" + message_;
136   return ret;
137 }
138 
139 string XmlBlasterException::getRawMessage() const
140 {
141    return message_;
142 }
143 
144 string XmlBlasterException::getVersionInfo() const
145 {
146    return versionInfo_;
147 }
148 
149 string XmlBlasterException::getTimestamp() const
150 {
151    if (timestamp_ == "") {
152       timestamp_ = lexical_cast<std::string>(TimestampFactory::getInstance().getTimestamp());
153    }
154    return timestamp_;
155 }
156 
157 string XmlBlasterException::getStackTraceStr() const
158 {
159    return stackTrace_;
160 }
161 
162 string XmlBlasterException::getEmbeddedMessage() const
163 {
164    return embeddedMessage_;
165 }
166 
167 string XmlBlasterException::getTransactionInfo() const
168 {
169    return transactionInfo_;
170 }
171 
172 bool XmlBlasterException::isInternal() const
173 {
174    return (errorCodeStr_.find("internal") == 0);
175 }
176 
177 bool XmlBlasterException::isResource() const
178 {
179    return (errorCodeStr_.find("resource") == 0);
180 }
181 
182 bool XmlBlasterException::isCommunication() const
183 {
184    return (errorCodeStr_.find("communication") == 0);
185 }
186 
187 bool XmlBlasterException::isUser() const
188 {
189    return (errorCodeStr_.find("user") == 0);
190 }
191 
192 bool XmlBlasterException::isTransaction() const
193 {
194    return (errorCodeStr_.find("transaction") == 0);
195 }
196 
197 /**
198  * Returns a stringified version of the exception
199  */
200 string XmlBlasterException::toString() const
201 {
202    return "errorCode=" + getErrorCodeStr() + " message=" + getRawMessage();
203 }
204 
205 /**
206  * Parsing what toString() produced
207  */
208 XmlBlasterException XmlBlasterException::parseFromString(string fromString)
209 {
210    string errorCode = fromString;
211    string reason = fromString;
212    size_t start = fromString.find("errorCode=");
213    size_t end = fromString.find(" message=");
214    if (start != string::npos) {
215       if (end != string::npos) {
216          try {
217             errorCode = fromString.substr(start+(sizeof("errorCode=")/sizeof("e")), end);
218          }
219          catch(const out_of_range &/*e1*/) {
220          }
221       }
222       else {
223          try {
224             errorCode = fromString.substr(start+(sizeof("errorCode=")/sizeof("e")));
225          }
226          catch(out_of_range &/*e2*/) {
227          }
228       }
229    }
230    if (end != string::npos) {
231       try {
232          reason = fromString.substr(end+(sizeof(" message=")/sizeof("e")));
233       }
234       catch(out_of_range &/*e3*/) {
235       }
236    }
237    try {
238       return XmlBlasterException(errorCode, "XmlBlasterException", "en", reason);
239    }
240    catch (...) {
241       return XmlBlasterException(INTERNAL_ILLEGALARGUMENT.errorCode, "XmlBlasterException", "en", fromString);
242    }
243 }
244 
245 /**
246  * Create a XML representation of the Exception.
247  * <pre>
248  *   &lt;exception errorCode='resource.outOfMemory'>
249  *      &lt;class>JavaClass&lt;/class>
250  *      &lt;message>&lt;![cdata[  bla bla ]]>&lt;/message>
251  *   &lt;/exception>
252  * </pre>
253  */
254 string XmlBlasterException::toXml() const
255 {
256    string buf = "<exception errorCode='" + getErrorCodeStr() + "'>\n";
257    if (getNode() != "")            buf += "   <node>" + getNode() + "</node>\n";
258    if (getLocation() != "")        buf += "   <location>" + getLocation() + "</location>\n";
259    if (getLang() != "en")          buf += "   <lang>" + getLang() + "</lang>\n";
260    if (getRawMessage() != "")      buf += "   <message><![CDATA[" + getRawMessage() + "]]></message>\n";
261    if (getVersionInfo() != "")     buf += "   <versionInfo>" + getVersionInfo() + "</versionInfo>\n";
262                                    buf += "   <timestamp>" + getTimestamp() + "</timestamp>\n";
263    if (getStackTraceStr() != "")   buf += "   <stackTrace><![CDATA[" + getStackTraceStr() + "]]></stackTrace>\n";
264    if (getEmbeddedMessage() != "") buf += "   <embeddedMessage><![CDATA[" + getEmbeddedMessage() + "]]></embeddedMessage>\n";
265    //                              buf += "   <transactionInfo><![CDATA[" + getTransactionInfo() + "]]></transactionInfo>\n";
266    buf += "</exception>";
267    return buf;
268 }
269 
270 #if defined(_ENABLE_STACK_TRACE_) && defined(__GNUC__)
271 string XmlBlasterException::getStackTrace(int maxNumOfLines)
272 {
273    void** arr = new void*[maxNumOfLines];
274    /*
275    > +Currently, the function name and offset can only be obtained on systems
276    > +that use the ELF binary format for programs and libraries.
277    Perhaps a reference to the addr2line program can be added here.  It
278    can be used to retrieve symbols even if the -rdynamic flag wasn't
279    passed to the linker, and it should work on non-ELF targets as well.
280    o  Under linux, gcc interprets it by setting the 
281       "-export-dynamic" option for ld, which has that effect, according
282       to the linux ld manpage.
283 
284    o Under IRIX it's ignored, and the program's happy as a clam.
285 
286    o Under SunOS-4.1, gcc interprets it by setting the -dc -dp
287       options for ld, which again forces the allocation of the symbol
288       table in the code produced (see ld(1) on a Sun).
289    */
290    int bt = backtrace(arr, maxNumOfLines);
291    char** list = backtrace_symbols(arr, bt); // malloc the return pointer, the entries don't need to be freed
292    string ret;
293    for (int i=0; i<bt; i++) {
294       if (list[i] != NULL) ret += list[i] + string("\n");
295    }
296    free(list);
297    delete[] arr;
298    if (ret.size() < 1) {
299       ret = "Creation of stackTrace failed";
300    }
301    return ret;
302 }
303 #else
304 string XmlBlasterException::getStackTrace(int )
305 {
306    return ""; //no stack trace provided in this system";
307 }
308 #endif
309 
310 }}} // namespaces


syntax highlighted by Code2HTML, v. 0.9.1