Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members | Related Pages | Examples

vos/corelibs/vos/message.cc

Go to the documentation of this file.
00001 /*
00002     This file is part of the Virtual Object System of
00003     the Interreality project (http://interreality.org).
00004 
00005     Copyright (C) 2001-2003 Peter Amstutz
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Lesser General Public
00009     License as published by the Free Software Foundation; either
00010     version 2 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Lesser General Public License for more details.
00016 
00017     You should have received a copy of the GNU Lesser General Public
00018     License along with this library; if not, write to the Free Software
00019     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
00020 
00021     Peter Amstutz <tetron@interreality.org>
00022 */
00023 
00024 #include "message.hh"
00025 #include "log.hh"
00026 #include "site.hh"
00027 #include "messagecontext.hh"
00028 
00029 #include <sys/types.h>
00030 #include <stdio.h>
00031 
00032 using namespace VOS;
00033 
00034 /** @file
00035     Implements Message.
00036  */
00037 
00038 int Message::refcount_debug_counter=0;
00039 
00040 #ifdef LEAKYSET_DEBUG
00041 set<Message*> Message::leakySet;
00042 #endif
00043 
00044 Message::Message() : mtime(0.0), source_site(0), messageContext(0), formattedString(0)
00045 {
00046     setMappingFunc(xmlFormatting);
00047     refcount_debug = ++refcount_debug_counter;
00048     incoming_debug = 0;
00049     LOG("message", 5, "created message " << refcount_debug);
00050 #ifdef LEAKYSET_DEBUG
00051     leakySet.insert(this);
00052 #endif
00053 }
00054 
00055 Message::Message(Message& m) : type(m.type), to(m.to),
00056     from(m.from), method(m.method), nonce(m.nonce), mtime(m.mtime),
00057     dependsOn(m.dependsOn), source_site(m.source_site),
00058     messageContext(m.messageContext), formattedString(m.formattedString),
00059     fields(m.fields), parse_extra(m.parse_extra), parse_buffer(m.parse_buffer),
00060     format_func(m.format_func), parse_func(m.parse_func)
00061 {
00062     refcount_debug = ++refcount_debug_counter;
00063     LOG("message", 5, "created message " << refcount_debug);
00064 #ifdef LEAKYSET_DEBUG
00065     leakySet.insert(this);
00066 #endif
00067 }
00068 
00069 
00070 Message::~Message()
00071 {
00072     if(formattedString) delete formattedString;
00073     LOG("refcount", 5, "message: deleting message [" << refcount_debug << "]");
00074     if(source_site) {
00075         LOG("refcount", 5, "about to release source site, count is " << source_site->getCount());
00076         source_site->release(); // acquired by: setSourceSite
00077     }
00078     if(messageContext) messageContext->release(); // acquired by: setMessageContext()
00079 #ifdef LEAKYSET_DEBUG
00080     leakySet.erase(this);
00081 #endif
00082 }
00083 
00084 #ifdef LEAKYSET_DEBUG
00085 void Message::printLeakySet()
00086 {
00087     LOG("leakyset", 5, "size of set is " << leakySet.size());
00088     for(set<Message*>::iterator i = leakySet.begin(); i != leakySet.end(); i++) {
00089         pREF(Site*, s, (*i)->getSourceSite(),
00090              if(s) {
00091                  LOG("leakyset", 5, "Source site is " << s->getURL().getString()
00092                      << " leaky msg is " << (*i)->getFormattedString());
00093              } else {
00094                  LOG("leakyset", 5, "No source site,  leaky msg is " << (*i)->getFormattedString());
00095              }
00096         );
00097     }
00098 }
00099 #endif
00100 
00101 #define RESET_FMTSTR { \
00102     if(formattedString) { \
00103         delete formattedString; \
00104         formattedString=0; \
00105     } \
00106 }
00107 
00108 
00109 void Message::setTo(const string& s) { to=s; RESET_FMTSTR; }
00110 void Message::setType(const string& s) { type=s; RESET_FMTSTR; }
00111 void Message::setFrom(const string& s) { from=s; RESET_FMTSTR; }
00112 void Message::setMethod(const string& s) { method=s; RESET_FMTSTR; }
00113 void Message::setNonce(const string& s) { nonce=s; RESET_FMTSTR; }
00114 void Message::setTime(double t) { mtime = t; RESET_FMTSTR; }
00115 void Message::setSourceSite(Site* s) {
00116     if(source_site) source_site->release(); // acquired by: setSourceSite
00117     if(s) s->acquire(); // released by: Message destructor or setSourceSite
00118     source_site=s;
00119 }
00120 void Message::setMessageContext(MessageContext* mb) {
00121     if(messageContext) messageContext->release(); // acquired by: this method (below)
00122     if(mb) mb->acquire(); // released by: Message destructor or setMessageContext()
00123     messageContext=mb;
00124 }
00125 void Message::setDependency(const string& nonce) {
00126     dependsOn = nonce;
00127     RESET_FMTSTR;
00128 }
00129 
00130 bool Message::hasTo() const
00131 {
00132     return (to != "");
00133 }
00134 
00135 bool Message::hasFrom() const
00136 {
00137     return (from != "");
00138 }
00139 
00140 bool Message::hasMethod() const
00141 {
00142     return (method != "");
00143 }
00144 
00145 bool Message::hasNonce() const
00146 {
00147     return (nonce != "");
00148 }
00149 
00150 bool Message::hasDependency() const
00151 {
00152     return (dependsOn != "");
00153 }
00154 
00155 string Message::getTo() const {
00156     string s = to;
00157     if(messageContext) messageContext->doSubstitution(s);
00158     return s;
00159 }
00160 string Message::getFrom() const {
00161     string s = from;
00162     if(messageContext) messageContext->doSubstitution(s);
00163     return s;
00164 }
00165 string Message::getMethod() const {
00166     string s = method;
00167     if(messageContext) messageContext->doSubstitution(s);
00168     return s;
00169 }
00170 const string& Message::getType() const { return type; }
00171 string Message::getNonce() const {
00172     string s = nonce;
00173     if(messageContext) messageContext->doSubstitution(s);
00174     return s;
00175 }
00176 double Message::getTime() const { return mtime; }
00177 Site* Message::getSourceSite() {
00178     if(source_site) {
00179         source_site->acquire(); // released by: the caller of this method
00180         return source_site;
00181     } else return 0;
00182 }
00183 MessageContext* Message::getMessageContext()
00184 {
00185     if(messageContext) {
00186         messageContext->acquire(); // released by: the caller of this method
00187         return messageContext;
00188     } else return 0;
00189 }
00190 string Message::getDependency() {
00191     string s = dependsOn;
00192     if(messageContext) messageContext->doSubstitution(s);
00193     return s;
00194 }
00195 int Message::getNumFields() const { return (int)fields.size(); }
00196 
00197 void Message::generateNonce()
00198 {
00199     char nonce[16];
00200     snprintf(nonce, sizeof(nonce), "%i", (int)rand());
00201     setNonce(string(nonce));
00202 }
00203 
00204 const Message::Field& Message::getField(const string& key) throw (NoSuchFieldError)
00205 {
00206     for(deque<Field>::iterator i = fields.begin(); i != fields.end(); i++) {
00207         if((*i).key == key) {
00208             (*i).value = (*i).source;
00209             if(messageContext && !(*i).quoted) messageContext->doSubstitution((*i).value);
00210             return (*i);
00211         }
00212     }
00213     throw NoSuchFieldError(string("No such field tag ") + key);
00214 }
00215 
00216 const Message::Field& Message::getField(int n) throw (NoSuchFieldError)
00217 {
00218     if(n < 0) n = (int)fields.size() + n + 1;
00219     if(n >= (int)fields.size()) throw NoSuchFieldError("Field index out of range");
00220     Field& f = fields[n];
00221     f.value = f.source;
00222     if(messageContext && !f.quoted) messageContext->doSubstitution(f.value);
00223     return f;
00224 }
00225 
00226 void Message::insertField(int n, const string& key, const string& val, bool quoted)
00227 {
00228 
00229     if(n < 0) n = (int)fields.size() + n + 1;
00230     Field f;
00231     f.key = key;
00232     f.source = val;
00233     f.quoted = quoted;
00234     if(!quoted) {
00235         // check for overrides (can't possible transmit unquoted string with there characters)
00236         for(unsigned int i = 0; i < val.length(); i++) {
00237             if(val[i] == '<' || val[i] == '>' || val[i] == '\0') {
00238                 f.quoted = true;
00239                 break;
00240             }
00241         }
00242     }
00243     fields.insert(fields.begin()+n, f);
00244     RESET_FMTSTR;
00245 }
00246 
00247 void Message::insertField(int n, const string& key, int val)
00248 {
00249 
00250     if(n < 0) n = (int)fields.size() + n + 1;
00251     Field f;
00252     f.key = key;
00253     char s[32];
00254     snprintf(s, sizeof(s), "%i", val);
00255     f.source = s;
00256     f.quoted = false;
00257 
00258     fields.insert(fields.begin()+n, f);
00259     RESET_FMTSTR;
00260 }
00261 
00262 void Message::insertField(int n, const string& key, double val)
00263 {
00264 
00265     if(n < 0) n = (int)fields.size() + n + 1;
00266     Field f;
00267     f.key = key;
00268     char s[32];
00269     snprintf(s, sizeof(s), "%f", val);
00270     f.source = s;
00271     f.quoted = false;
00272     fields.insert(fields.begin()+n, f);
00273     RESET_FMTSTR;
00274 }
00275 
00276 void Message::removeField(int n)
00277 {
00278     if(n < 0) n = (int)fields.size() + n;
00279     fields.erase(fields.begin()+n);
00280     RESET_FMTSTR;
00281 }
00282 
00283 void Message::removeField(const string& key)
00284 {
00285     for(unsigned int i=0; i < fields.size(); i++) {
00286         if(fields[i].key==key) {
00287             fields.erase(fields.begin()+i);
00288             break;
00289         }
00290     }
00291     RESET_FMTSTR;
00292 }
00293 
00294 
00295 void Message::setMappingFunc(string* (*func)(const string& type,
00296                                              const string& to,
00297                                              const string& from,
00298                                              const string& method,
00299                                              const string& nonce,
00300                                              const string& dependsOn,
00301                                              double mtime,
00302                                              const deque<Message::Field>& fields,
00303                                              bool withLength))
00304 {
00305     format_func=func;
00306     RESET_FMTSTR;
00307 }
00308 
00309 const string& Message::getFormattedString(bool withLength)
00310 {
00311     if(formattedString != 0) return *formattedString;
00312     else return *(formattedString = format_func(type, to, from, method, nonce, dependsOn, mtime, fields, withLength));
00313 }
00314 
00315 string Message::getLoggableString()
00316 {
00317     string s;
00318     string n;
00319 
00320     s += "<" + type + " ";
00321     n = to;
00322     if(messageContext) messageContext->doSubstitution(n);
00323     s += "to=\"" + n + "\"";
00324 
00325     n = from;
00326     if(messageContext) messageContext->doSubstitution(n);
00327     s += "\n  from=\"" + n + "\"";
00328 
00329     n = method;
00330     if(messageContext) messageContext->doSubstitution(n);
00331     s += "\n  method=\"" + n + "\"";
00332 
00333     n = nonce;
00334     if(messageContext) messageContext->doSubstitution(n);
00335     if(n != "") s += "\n  nonce=\"" + n + "\"";
00336 
00337     n = dependsOn;
00338     if(messageContext) messageContext->doSubstitution(n);
00339     if(n != "") s += "\n  depends=\"" + n + "\"";
00340 
00341     if(mtime != 0.0) {
00342         char timing[16];
00343         snprintf(timing, sizeof(timing), "%6.6f", mtime);
00344         s += "\n  time=\"";
00345         s += timing;
00346         s += "\"";
00347     }
00348 
00349     if(fields.size() == 0) {
00350         s += " />";
00351     } else {
00352         s += ">";
00353         deque<Message::Field>::iterator f=fields.begin();
00354 
00355         while(f != fields.end()) {
00356             if((*f).source == "") {
00357                 s += "<" + (*f).key + " />\n    ";
00358             } else {
00359                 (*f).value = (*f).source;
00360                 if(messageContext && !(*f).quoted) messageContext->doSubstitution((*f).value);
00361                 s += "\n    <" + (*f).key + ">" + (*f).value + "</" + (*f).key + ">";
00362             }
00363             f++;
00364         }
00365         s += "\n</" + type + ">";
00366     }
00367 
00368     return s;
00369 }
00370 
00371 /*
00372 int Message::parseUpdate(const string& data)
00373 {
00374     int oldsize=parse_buffer.size();
00375     parse_buffer.append(data);
00376 
00377     int ret=parse_func(*this, parse_extra, parse_buffer);
00378     if(ret > 0) {
00379         parse_buffer.erase(parse_buffer.begin(), parse_buffer.end());
00380         if(formattedString != 0) {
00381             delete formattedString;
00382             formattedString=0;
00383         }
00384         return (ret - oldsize);
00385     } else {
00386         fields.resize(0);
00387         return 0;
00388     }
00389 }
00390 */
00391 
00392 /* these are functions for the parsing/formatting */
00393 
00394 string* VOS::xmlFormatting(const string& type,
00395                            const string& to,
00396                            const string& from,
00397                            const string& method,
00398                            const string& nonce,
00399                            const string& dependsOn,
00400                            double mtime,
00401                            const deque<Message::Field>& fields,
00402                            bool withLength)
00403 {
00404     string* s=new string();
00405 
00406     *s += "<" + type + " ";
00407     if(withLength) *s += "length=\"\"\n";
00408     if(to != "") *s += "to=\"" + to + "\"\n";
00409     if(from != "") *s += "from=\"" + from + "\"\n";
00410     if(method != "") *s += "method=\"" + method + "\"";
00411     if(nonce != "") *s += "\nnonce=\"" + nonce + "\"";
00412     if(dependsOn != "") *s += "\ndepends=\"" + dependsOn + "\"";
00413     if(mtime != 0.0) {
00414         char timing[16];
00415         snprintf(timing, sizeof(timing), "%6.6f", mtime);
00416         *s += "\ntime=\"";
00417         *s += timing;
00418         *s += "\"";
00419     }
00420 
00421     if(fields.size() == 0) {
00422         *s += " />";
00423     } else {
00424         *s += ">\n";
00425         deque<Message::Field>::const_iterator f=fields.begin();
00426 
00427         while(f != fields.end()) {
00428             if((*f).source == "") {
00429                 *s += "<" + (*f).key + " />\n";
00430             } else {
00431                 if((*f).quoted) {
00432                     *s += "<" + (*f).key + " ";
00433                     *s += "length=\"";
00434                     char n[16];
00435                     snprintf(n, sizeof(n), "%i", (*f).source.length());
00436                     *s += n;
00437                     *s += "\">" + (*f).source + "</" + (*f).key + ">\n";
00438                 } else {
00439                     *s += "<" + (*f).key + ">" + (*f).source + "</" + (*f).key + ">\n";
00440                 }
00441             }
00442             f++;
00443         }
00444         *s += "</" + type + ">";
00445     }
00446 
00447     if(withLength) {
00448         unsigned int size = (unsigned int)s->size();
00449         char len[16];
00450         int width=snprintf(len, sizeof(len), "%i", size);
00451         size += (unsigned int)strlen(len);
00452         if(width < snprintf(len, sizeof(len), "%i", size)) snprintf(len, sizeof(len), "%i", size+1);
00453         // '< length="' is 10 characters
00454         s->insert(10+type.size(), len);
00455         LOG("message", 5, "generated message exactly " << (unsigned int)s->size() << " bytes long");
00456     }
00457 
00458     return s;
00459 }
00460 
00461 

Generated on Tue Aug 12 03:55:40 2003 for Interreality Project - VOS by doxygen 1.3.2