session.C

00001 /*
00002  * This file is part of the "Archon" framework.
00003  * (http://files3d.sourceforge.net)
00004  *
00005  * Copyright  2002 by Kristian Spangsege and Brian Kristiansen.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and
00008  * its documentation under the terms of the GNU General Public License is
00009  * hereby granted. No representations are made about the suitability of
00010  * this software for any purpose. It is provided "as is" without express
00011  * or implied warranty. See the GNU General Public License
00012  * (http://www.gnu.org/copyleft/gpl.html) for more details.
00013  *
00014  * The characters in this file are ISO8859-1 encoded.
00015  *
00016  * The documentation in this file is in "Doxygen" style
00017  * (http://www.doxygen.org).
00018  */
00019 
00020 #include <archon/util/cxx_demangle.H>
00021 #include <archon/util/uri.H>
00022 
00023 #include <archon/x3d/server/network.H>
00024 #include <archon/x3d/server/parse_xml.H>
00025 
00026 #include <archon/x3d/sai/exception.H>
00027 #include <archon/x3d/sai/sai.H>
00028 #include <archon/x3d/sai/session.H>
00029 #include <archon/x3d/sai/listener.H>
00030 #include <archon/x3d/sai/route.H>
00031 
00032 #define CORBA_ENTRY_D(x) try { session->x; } \
00033 catch(CORBA::UserException &) { throw; } \
00034 catch(ForwardDestroyedException &) {} \
00035 catch(...) { string m = SAI::exceptionCatchShortExplanation(); \
00036 throw x3d::sai::ServerErrorException(m.c_str()); }
00037 
00038 #define CORBA_ENTRY_V(x) try { session->x; } \
00039 catch(CORBA::UserException &) { throw; } \
00040 catch(ForwardDestroyedException &) \
00041 { throw x3d::sai::InvalidSessionException(); } \
00042 catch(...) { string m = SAI::exceptionCatchShortExplanation(); \
00043 throw x3d::sai::ServerErrorException(m.c_str()); }
00044 
00045 #define CORBA_ENTRY_R(x) try { return session->x; } \
00046 catch(CORBA::UserException &) { throw; } \
00047 catch(ForwardDestroyedException &) \
00048 { throw x3d::sai::InvalidSessionException(); } \
00049 catch(...) { string m = SAI::exceptionCatchShortExplanation(); \
00050 throw x3d::sai::ServerErrorException(m.c_str()); }
00051 
00052 namespace Archon
00053 {
00054   namespace X3D
00055   {
00056     namespace SAI
00057     {
00058       using namespace Utilities;
00059   
00060       struct Session::Servant:
00061         POA_x3d::sai::Session, PortableServer::RefCountServantBase
00062       {
00063         const BackRef<SAI::Session> session;
00064 
00065         Servant(Ref<SAI::Session> session): session(session) {}
00066 
00067         ~Servant()
00068         {
00069         }
00070 
00071         // Session (or Browser) services
00072 
00073         char *getServerName()
00074         {
00075           CORBA_ENTRY_R(getServerName());
00076         }
00077 
00078         CORBA::Double getCurrentFrameRate()
00079         {
00080           CORBA_ENTRY_R(getCurrentFrameRate());
00081         }
00082 
00083         CORBA::ULong createApplicationScene(const char *baseUri,
00084                                             CORBA::Boolean localFileUri)
00085         {
00086           CORBA_ENTRY_R(createApplicationScene(baseUri, localFileUri));
00087         }
00088 
00089         CORBA::ULong loadApplicationScene(const char *uri,
00090                                           CORBA::Boolean localFileUri)
00091         {
00092           CORBA_ENTRY_R(loadApplicationScene(uri, localFileUri));
00093         }
00094 
00095         void launchApplicationScene(CORBA::ULong contextId)
00096         {
00097           CORBA_ENTRY_V(launchApplicationScene(contextId));
00098         }
00099 
00100         void withdrawApplicationScene(CORBA::ULong contextId)
00101         {
00102           CORBA_ENTRY_V(withdrawApplicationScene(contextId));
00103         }
00104 
00105         void beginUpdate()
00106         {
00107           CORBA_ENTRY_V(beginUpdate());
00108         }
00109 
00110         void endUpdate()
00111         {
00112           CORBA_ENTRY_V(endUpdate());
00113         }
00114 
00115         void print(const char *s)
00116         {
00117           CORBA_ENTRY_V(print(s));
00118         }
00119 
00120         void setSynchronizedChangesEnabled(CORBA::Boolean enabled)
00121         {
00122           CORBA_ENTRY_V(setSynchronizedChangesEnabled(enabled));
00123         }
00124 
00125         void disposeBatch(const x3d::sai::DisposeSeq &contexts,
00126                           const x3d::sai::DisposeSeq &nodes)
00127         {
00128           CORBA_ENTRY_V(disposeBatch(contexts, nodes));
00129         }
00130 
00131         void disposeSession()
00132         {
00133           CORBA_ENTRY_D(disposeSession());
00134         }
00135 
00136 
00137         // ExecutionContext services
00138 
00139         char *getBaseUri(CORBA::ULong contextId)
00140         {
00141           CORBA_ENTRY_R(getBaseUri(contextId));
00142         }
00143 
00144         CORBA::ULong getRootGroup(CORBA::ULong contextId)
00145         {
00146           CORBA_ENTRY_R(getRootGroup(contextId));
00147         }
00148 
00149         void setRootGroup(CORBA::ULong contextId, CORBA::ULong nodeId)
00150         {
00151           CORBA_ENTRY_V(setRootGroup(contextId, nodeId));
00152         }
00153 
00154         CORBA::ULong createNode(CORBA::ULong contextId, const char *typeName)
00155         {
00156           CORBA_ENTRY_R(createNode(contextId, typeName));
00157         }
00158 
00159         CORBA::ULong createNodeFast(CORBA::ULong contextId, CORBA::ULong typeId)
00160         {
00161           CORBA_ENTRY_R(createNode(contextId, typeId));
00162         }
00163 
00164         CORBA::ULong getNode(CORBA::ULong contextId, const char *nodeName)
00165         {
00166           CORBA_ENTRY_R(getNode(contextId, nodeName));
00167         }
00168 
00169         void addRoute(CORBA::ULong contextId,
00170                       CORBA::ULong fromNodeId, CORBA::ULong fromFieldId,
00171                       CORBA::ULong toNodeId, CORBA::ULong toFieldId)
00172         {
00173           CORBA_ENTRY_V(addRoute(contextId, fromNodeId, fromFieldId,
00174                            toNodeId, toFieldId));
00175         }
00176 
00177         void delRoute(CORBA::ULong contextId,
00178                       CORBA::ULong fromNodeId, CORBA::ULong fromFieldId,
00179                       CORBA::ULong toNodeId, CORBA::ULong toFieldId)
00180         {
00181           CORBA_ENTRY_V(delRoute(contextId, fromNodeId, fromFieldId,
00182                            toNodeId, toFieldId));
00183         }
00184 
00185         CORBA::ULong createGroupFromStream(CORBA::ULong contextId,
00186                                            x3d::sai::StreamReader_ptr r)
00187         {
00188           CORBA_ENTRY_R(createGroupFromStream(contextId, r));
00189         }
00190 
00191         void disposeContext(CORBA::ULong contextId)
00192         {
00193           CORBA_ENTRY_V(disposeContext(contextId));
00194         }
00195 
00196 
00197         // Node services
00198 
00199         char *getNodeType(CORBA::ULong nodeId)
00200         {
00201           CORBA_ENTRY_R(getNodeType(nodeId));
00202         }
00203 
00204         CORBA::ULong getField(CORBA::ULong nodeId, const char *name)
00205         {
00206           CORBA_ENTRY_R(getField(nodeId, name));
00207         }
00208 
00209         void disposeNode(CORBA::ULong nodeId)
00210         {
00211           CORBA_ENTRY_V(disposeNode(nodeId));
00212         }
00213 
00214 
00215         // Field services
00216 
00217         CORBA::ULong getFieldType(CORBA::ULong nodeId, CORBA::ULong fieldId)
00218         {
00219           CORBA_ENTRY_R(getFieldType(nodeId, fieldId));
00220         }
00221 
00222         char *getFieldName(CORBA::ULong nodeId, CORBA::ULong fieldId)
00223         {
00224           CORBA_ENTRY_R(getFieldName(nodeId, fieldId));
00225         }
00226 
00227         CORBA::ULong getFieldAccessType(CORBA::ULong nodeId,
00228                                         CORBA::ULong fieldId)
00229         {
00230           CORBA_ENTRY_R(getFieldAccessType(nodeId, fieldId));
00231         }
00232 
00233         void registerFieldInterest(CORBA::ULong nodeId, CORBA::ULong fieldId,
00234                                    CORBA::ULong cookie)
00235         {
00236           CORBA_ENTRY_V(registerFieldInterest(nodeId, fieldId, cookie));
00237         }
00238 
00239         void unRegisterFieldInterest(CORBA::ULong nodeId,
00240                                      CORBA::ULong fieldId,
00241                                      CORBA::ULong cookie)
00242         {
00243           CORBA_ENTRY_V(unRegisterFieldInterest(nodeId, fieldId, cookie));
00244         }
00245 
00246         x3d::sai::Value *getFieldValue(CORBA::ULong nodeId,
00247                                        CORBA::ULong fieldId)
00248         {
00249           CORBA_ENTRY_R(getFieldValue(nodeId, fieldId));
00250         }
00251 
00252         void setFieldValue(CORBA::ULong nodeId, CORBA::ULong fieldId,
00253                            const x3d::sai::Value &value)
00254         {
00255           CORBA_ENTRY_V(setFieldValue(nodeId, fieldId, value));
00256         }
00257 
00258         x3d::sai::Value *getFieldValueAt(CORBA::ULong nodeId,
00259                                          CORBA::ULong fieldId,
00260                                          CORBA::ULong index)
00261         {
00262           CORBA_ENTRY_R(getFieldValueAt(nodeId, fieldId, index));
00263         }
00264 
00265         void setFieldValueAt(CORBA::ULong nodeId, CORBA::ULong fieldId,
00266                              CORBA::ULong index, const x3d::sai::Value &value)
00267         {
00268           CORBA_ENTRY_V(setFieldValueAt(nodeId, fieldId, index, value));
00269         }
00270 
00271         void setFieldValueAdd(CORBA::ULong nodeId, CORBA::ULong fieldId,
00272                               const x3d::sai::Value &value)
00273         {
00274           CORBA_ENTRY_V(setFieldValueAdd(nodeId, fieldId, value));
00275         }
00276 
00277         void setFieldValueDel(CORBA::ULong nodeId, CORBA::ULong fieldId,
00278                               const x3d::sai::Value &value)
00279         {
00280           CORBA_ENTRY_V(setFieldValueDel(nodeId, fieldId, value));
00281         }
00282 
00283         void disposeField(CORBA::ULong fieldId)
00284         {
00285           CORBA_ENTRY_V(disposeField(fieldId));
00286         }
00287       };
00288 
00289 
00290       struct Reader: Stream::ReaderBase<char>
00291       {
00292         x3d::sai::StreamReader_var reader;
00293 
00294         bool eoi;
00295 
00296         Reader(x3d::sai::StreamReader_ptr r): eoi(false)
00297         {
00298           reader = x3d::sai::StreamReader::_duplicate(r);
00299         }
00300 
00301         ~Reader()
00302         {{
00303           try { reader->dispose(); }
00304           catch(...) {}
00305         }}
00306 
00307         int read(char *buffer, int size)
00308           throw(Stream::ReadException, UnexpectedException)
00309         {
00310           if(eoi) return 0;
00311           x3d::sai::chararray_var a;
00312           try { a = reader->read(size); }
00313           catch(x3d::sai::StreamReadException &e)
00314           {
00315             ARCHON_THROW1(Stream::ReadException, string(e.message));
00316           }
00317           catch(...)
00318           {
00319             ARCHON_THROW1(Stream::ReadException, "Caught unknown exception");
00320           }
00321           if(a->length()>(unsigned)size)
00322             ARCHON_THROW1(Stream::ReadException, "Too much data");
00323           if(a->length()<(unsigned)size) eoi = true;
00324           for(unsigned i=0; i<a->length(); ++i) buffer[i] = a[i];
00325           return a->length();
00326         }
00327       };
00328 
00329       struct ApplicationSceneReaper: Thread
00330       {
00331         void main()
00332         {
00333           list<Ref<ApplicationScene> >::iterator i = launchedScenes.begin();
00334           while(i != launchedScenes.end())(*i++)->withdraw();
00335         }
00336 
00337         list<Ref<ApplicationScene> > launchedScenes;
00338       };
00339 
00340       struct Session::ExternalEvent
00341       {
00342         const Ref<const ValueBase> value;
00343         const unsigned long cookie;
00344         
00345         ExternalEvent(const ValueBase *value, unsigned long cookie):
00346           value(value), cookie(cookie) {}
00347       };
00348 
00349       struct Session::ExternalEventQueue: Thread
00350       {
00351         ExternalEventQueue(Ref<Session>, Time heartbeat);
00352 
00353         ~ExternalEventQueue()
00354         {
00355         }
00356 
00357         const BackRef<Session> session;
00358         Time heartbeat;
00359 
00360         Mutex mutex;
00361         Condition nonEmpty;
00362         list<ExternalEvent> eventQueue;
00363         bool hasTerminated;
00364         bool flushRequest;
00365         bool flushing;
00366         Condition flushed;
00367 
00368         void main();
00369 
00370         void addEvent(const ValueBase *, unsigned long cookie);
00371 
00376         void flush();
00377       };
00378 
00379 
00380       Session::Session(Ref<Listener> listener,
00381                        x3d::sai::Application_ptr a):
00382         listener(listener),
00383         orb(listener->getOrb()),
00384         application(x3d::sai::Application::_duplicate(a)),
00385         active(false),
00386         buffered(false),
00387         synchronizedChanges(true)
00388       {
00389       }
00390 
00391       Session::~Session() 
00392       {
00393       }
00394 
00395 
00396       void Session::refForwardDestroy()
00397       {
00398         /*
00399         try { listener->server->getLogger()->log(nodeMap.disp()); }
00400         catch(...) {}
00401         */
00402 
00403         // Stop and destroy the ExternalEventQueue object. This breaks
00404         // a reference loop which includes one backward reference to
00405         // ourself.
00406         externalEventQueue->terminate(); // Stop async activity
00407         externalEventQueue.reset();
00408 
00409         deactivate();
00410         nodeMap.clear();
00411         contextMap.clear();
00412         routeHeads.clear();
00413 
00414         // Withdraw application scenes from scene graph (No more
00415         // scenes will ever be added since at this point no further
00416         // access to this object can be attempted except for that
00417         // caused by this very call.)
00418         if(launchedScenes.empty()) return;
00419         Ref<ApplicationSceneReaper> r = new ApplicationSceneReaper();
00420         swap(launchedScenes, r->launchedScenes);
00421         Thread::start(r);
00422       }
00423 
00424       x3d::sai::Session_ptr Session::createServant(Time heartbeat)
00425       {
00426         Mutex::Lock lock(mutex);
00427         return activate(heartbeat);
00428       }
00429 
00430       x3d::sai::Session_ptr Session::activate(Time heartbeat)
00431       {
00432         if(active) deactivate();
00433         externalEventQueue = new ExternalEventQueue(this, heartbeat);
00434         Thread::start(externalEventQueue);
00435         ServantRef<Servant> servant = new Servant(this);
00436         servantId = orb.getPoa()->activate_object(servant.get());
00437         x3d::sai::Session_var ref = servant->_this();
00438         active = true;
00439         return ref._retn();
00440       }
00441 
00442       void Session::deactivate()
00443       {
00444         if(!active) return;
00445         orb.getPoa()->deactivate_object(servantId);
00446         active = false;
00447       }
00448 
00449       void Session::executeChanges()
00450       {
00451         Time time = listener->server->getNextTimeStamp();
00452         while(!changeQueue.empty())
00453         {
00454           try
00455           {
00456             changeQueue.front()->apply(time);
00457           }
00458           catch(NodeBase::AccessException &) {}
00459           catch(NodeBase::RangeException &) {}
00460           changeQueue.pop();
00461         }
00462       }
00463 
00464 
00465       unsigned long Session::node2id(Ref<NodeBase> n)
00466       {
00467         if(!n) return 0;
00468         long t = n->getType()->getIndex();
00469         // if(n>255) ARCHON_THROW1(InternalException, "Node index overflow");
00470         return static_cast<unsigned long>(nodeMap.get(n)) <<
00471           NodeType::maxIndexBits | t;
00472       }
00473 
00474       Ref<NodeBase> Session::id2node(unsigned long i)
00475         throw(IllegalNodeIdException)
00476       {
00477         if(!i) return 0;
00478         Ref<NodeBase> n = nodeMap(i >> NodeType::maxIndexBits);
00479         if(!n) ARCHON_THROW(Porter::IllegalNodeIdException);
00480         return n;
00481       }
00482 
00483 
00484       // Session (or Browser) services
00485 
00486       char *Session::getServerName()
00487       {
00488         string n = listener->server->getName();
00489         return CORBA::string_dup(n.c_str());
00490       }
00491 
00492       CORBA::Double Session::getCurrentFrameRate()
00493       {
00494         return listener->server->getFrameRate();
00495       }
00496 
00497       CORBA::ULong
00498       Session::createApplicationScene(const char *u,
00499                                       CORBA::Boolean localFileUri)
00500       {
00501         Uri baseUri(u);
00502 
00503         Ref<ApplicationScene> context =
00504           new ApplicationScene(listener->server.getRef(),
00505                                  baseUri, localFileUri ? this : 0);
00506         CORBA::ULong v = contextMap.get(context, true);
00507         return v;
00508       }
00509 
00510       CORBA::ULong
00511       Session::loadApplicationScene(const char *u,
00512                                     CORBA::Boolean localFileUri)
00513       {
00514         Uri uri(u);
00515 
00516         Ref<ApplicationScene> context =
00517           new ApplicationScene(listener->server.getRef(),
00518                                  uri, localFileUri ? this : 0);
00519 
00520         Ref<Loader> loader = listener->server->getLoader();
00521         if(loader) try
00522         {
00523           Ref<Web::Client::Response> response = loader->getWebClient()->
00524             request(Web::Client::Request::get(uri));
00525           Ref<Group> rootGroup = new Group(Ref<ExecutionContext>(context));
00526           XML::parse(context, rootGroup, response,
00527                      false, this, uri.getFile());
00528           context->setRootGroup(rootGroup);
00529         }
00530         catch(Web::RequestException &e)
00531         {
00532           string message = e.getMessage();
00533           throw x3d::sai::FileRequestException(message.c_str());
00534         }
00535         catch(ParseException &)
00536         {
00537           throw x3d::sai::InvalidX3DException();
00538         }
00539 
00540         return contextMap.get(context, true);
00541       }
00542 
00552       void Session::launchApplicationScene(CORBA::ULong ci)
00553       {
00554         Ref<ExecutionContext> c = contextMap(ci);
00555         if(!c) throw x3d::sai::InvalidExecutionContextException();
00556         ApplicationScene *applicationScene =
00557           dynamic_cast<ApplicationScene *>(c.get());
00558         if(!applicationScene)
00559           throw x3d::sai::InvalidExecutionContextException();
00560 
00561         applicationScene->launch(listener->getApplicationContainer());
00562         
00563         Mutex::Lock lock(mutex);
00564         launchedScenes.push_back(Ref<ApplicationScene>(applicationScene));
00565       }
00566 
00567       void Session::withdrawApplicationScene(CORBA::ULong ci)
00568       {
00569         Ref<ExecutionContext> c = contextMap(ci);
00570         if(!c) throw x3d::sai::InvalidExecutionContextException();
00571         ApplicationScene *applicationScene =
00572           dynamic_cast<ApplicationScene *>(c.get());
00573         if(!applicationScene)
00574           throw x3d::sai::InvalidExecutionContextException();
00575 
00576         {
00577           Mutex::Lock lock(mutex);
00578           list<Ref<ApplicationScene> >::iterator i =
00579             find(launchedScenes.begin(), launchedScenes.end(), Ref<ApplicationScene>(applicationScene));
00580           if(i == launchedScenes.end()) throw x3d::sai::NotLaunchedException();
00581           launchedScenes.erase(i);
00582         }
00583 
00584         applicationScene->withdraw();
00585       }
00586 
00587       void Session::beginUpdate()
00588       {
00589         Mutex::Lock lock(mutex);
00590         buffered = true;
00591       }
00592 
00593       void Session::endUpdate()
00594       {
00595         Mutex::Lock lock(mutex);
00596         executeChanges();
00597         buffered = false;
00598       }
00599 
00600       void Session::print(const char *s)
00601       {
00602         listener->server->print(s);
00603       }
00604 
00605       void Session::setSynchronizedChangesEnabled(CORBA::Boolean enabled)
00606       {
00607         Mutex::Lock lock(mutex);
00608         synchronizedChanges = enabled;
00609       }
00610 
00611       void Session::disposeBatch(const x3d::sai::DisposeSeq &c,
00612                                  const x3d::sai::DisposeSeq &n)
00613       {
00614         for(unsigned i=0; i<c.length(); ++i)
00615         {
00616           const x3d::sai::DisposeEntry &e = c[i];
00617           contextMap.remove(e.id, e.transCount);
00618         }
00619 
00620         for(unsigned i=0; i<n.length(); ++i)
00621         {
00622           const x3d::sai::DisposeEntry &e = n[i];
00623           nodeMap.remove(e.id >> NodeType::maxIndexBits, e.transCount);
00624         }
00625       }
00626 
00636       void Session::disposeSession()
00637       {
00638         // Deactivate CORBA servant if activated
00639         deactivate();
00640 
00641         // Destroy the only reference to this object that would have
00642         // remained after this service call withdraws. This must lead
00643         // to a destruction of this Session object.
00644         try { listener->removeSession(this); }
00645         catch(ForwardDestroyedException &) {}
00646       }
00647 
00648 
00649       // ExecutionContext services
00650 
00651       char *Session::getBaseUri(CORBA::ULong ci)
00652       {
00653         Ref<ExecutionContext> c = contextMap(ci);
00654         if(!c) throw x3d::sai::InvalidExecutionContextException();
00655         return CORBA::string_dup(c->getBaseUri().toString().c_str());
00656       }
00657 
00665       CORBA::ULong Session::getRootGroup(CORBA::ULong ci)
00666       {
00667         Ref<ExecutionContext> c = contextMap(ci);
00668         SceneBase *s = dynamic_cast<SceneBase *>(c.get());
00669         if(!s) throw x3d::sai::InvalidExecutionContextException();
00670         return node2id(s->getRootGroup());
00671       }
00672 
00680       void Session::setRootGroup(CORBA::ULong ci, CORBA::ULong ni)
00681       {
00682         Ref<ExecutionContext> c = contextMap(ci);
00683         SceneBase *s = dynamic_cast<SceneBase *>(c.get());
00684         if(!s) throw x3d::sai::InvalidExecutionContextException();
00685         try
00686         {
00687           Ref<NodeBase> n = id2node(ni);
00688           Ref<Group> g = dynamic_cast<Group *>(n.get());
00689           if(!g && n) throw x3d::sai::InvalidNodeException();
00690           s->setRootGroup(g);
00691         }
00692         catch(IllegalNodeIdException &)
00693         {
00694           throw x3d::sai::InvalidNodeException();
00695         }
00696       }
00697 
00698       CORBA::ULong Session::createNode(CORBA::ULong ci, const char *n)
00699       {
00700         Ref<ExecutionContext> c = contextMap(ci);
00701         if(!c) throw x3d::sai::InvalidExecutionContextException();
00702         const NodeType *t = NodeType::lookup(n);
00703         if(!t || !t->isUserInstantiable())
00704           throw x3d::sai::InvalidNameException();
00705         return node2id(t->instantiate(c));
00706       }
00707 
00708       CORBA::ULong Session::createNode(CORBA::ULong ci, CORBA::ULong ti)
00709       {
00710         Ref<ExecutionContext> c = contextMap(ci);
00711         if(!c) throw x3d::sai::InvalidExecutionContextException();
00712         if(ti >= NodeType::getTotalNumber())
00713           throw x3d::sai::InvalidTypeException();
00714         const NodeType *t = NodeType::get(ti);
00715         if(!t->isUserInstantiable())
00716           throw x3d::sai::InvalidTypeException();
00717         return node2id(t->instantiate(c));
00718       }
00719 
00720       CORBA::ULong Session::getNode(CORBA::ULong ci, const char *n)
00721       {
00722         Ref<ExecutionContext> c = contextMap(ci);
00723         if(!c) throw x3d::sai::InvalidExecutionContextException();
00724         Ref<NodeBase> node = c->lookupNode(n);
00725         if(!node) throw x3d::sai::InvalidNameException();
00726         return node2id(node);
00727       }
00728 
00729       void Session::addRoute(CORBA::ULong ci,
00730                              CORBA::ULong fni, CORBA::ULong ffi,
00731                              CORBA::ULong tni, CORBA::ULong tfi)
00732       {
00733         Ref<ExecutionContext> c = contextMap(ci);
00734         if(!c) throw x3d::sai::InvalidExecutionContextException();
00735         try
00736         {
00737           Ref<NodeBase> sourceNode = id2node(fni);
00738           const FieldBase *sourceField =
00739             FieldBase::fetch(ffi, sourceNode.get());
00740           Ref<NodeBase> targetNode = id2node(tni);
00741           const FieldBase *targetField =
00742             FieldBase::fetch(tfi, targetNode.get());
00743           if(!sourceField || !targetField)
00744             throw x3d::sai::InvalidFieldException();
00745           if(sourceNode->context != c || targetNode->context != c)
00746             throw x3d::sai::InvalidNodeException();
00747 
00748           // Field input/output capabilities
00749           if(!sourceField->getIsEventSource() ||
00750              !targetField->getIsEventTarget())
00751             throw x3d::sai::InvalidAccessTypeException();
00752 
00753           // Type conformance
00754           if(sourceField->getType() != targetField->getType())
00755             throw x3d::sai::InvalidAccessTypeException();
00756 
00757           // Injective node type restriction
00758           if(const NodeFieldBase *s =
00759              dynamic_cast<const NodeFieldBase *>(sourceField))
00760           {
00761             const NodeFieldBase *t =
00762               dynamic_cast<const NodeFieldBase *>(targetField);
00763             if(!s->getNodeType()->isDerivedFrom(t->getNodeType()))
00764               throw x3d::sai::InvalidAccessTypeException();
00765           }
00766 
00767           handleChange(new RouteChange(sourceNode, sourceField,
00768                                        targetNode, targetField));
00769         }
00770         catch(IllegalNodeIdException &)
00771         {
00772           throw x3d::sai::InvalidNodeException();
00773         }
00774       }
00775 
00776       void Session::delRoute(CORBA::ULong ci,
00777                              CORBA::ULong fni, CORBA::ULong ffi,
00778                              CORBA::ULong tni, CORBA::ULong tfi)
00779       {
00780         Ref<ExecutionContext> c = contextMap(ci);
00781         if(!c) throw x3d::sai::InvalidExecutionContextException();
00782         try
00783         {
00784           Ref<NodeBase> sourceNode = id2node(fni);
00785           const FieldBase *sourceField =
00786             FieldBase::fetch(ffi, sourceNode.get());
00787           Ref<NodeBase> targetNode = id2node(tni);
00788           const FieldBase *targetField =
00789             FieldBase::fetch(tfi, targetNode.get());
00790           if(!sourceField || !targetField)
00791             throw x3d::sai::InvalidFieldException();
00792           if(sourceNode->context != c || targetNode->context != c)
00793             throw x3d::sai::InvalidNodeException();
00794 
00795           // Field input/output capabilities
00796           if(!sourceField->getIsEventSource() ||
00797              !targetField->getIsEventTarget())
00798             throw x3d::sai::InvalidAccessTypeException();
00799 
00800           // Type conformance
00801           if(sourceField->getType() != targetField->getType())
00802             throw x3d::sai::InvalidAccessTypeException();
00803 
00804           // Injective node type restriction
00805           if(const NodeFieldBase *s =
00806              dynamic_cast<const NodeFieldBase *>(sourceField))
00807           {
00808             const NodeFieldBase *t =
00809               dynamic_cast<const NodeFieldBase *>(targetField);
00810             if(!s->getNodeType()->isDerivedFrom(t->getNodeType()))
00811               throw x3d::sai::InvalidAccessTypeException();
00812           }
00813 
00814           handleChange(new RouteChange(sourceNode, sourceField,
00815                                        targetNode, targetField, true));
00816         }
00817         catch(IllegalNodeIdException &)
00818         {
00819           throw x3d::sai::InvalidNodeException();
00820         }
00821       }
00822 
00823       CORBA::ULong Session::createGroupFromStream(CORBA::ULong ci,
00824                                                   x3d::sai::StreamReader_ptr r)
00825       {
00826         Ref<ExecutionContext> c = contextMap(ci);
00827         if(!c) throw x3d::sai::InvalidExecutionContextException();
00828         Ref<GroupingNode> g = new Group(c);
00829         try
00830         {
00831           XML::parse(c, g, new Reader(r), false, this, "<SAI parse request>");
00832         }
00833         catch(ParseException &)
00834         {
00835           throw x3d::sai::InvalidX3DException();
00836         }
00837         return node2id(g);
00838       }
00839 
00840       void Session::disposeContext(CORBA::ULong ci)
00841       {
00842         contextMap.remove(ci);
00843       }
00844 
00845 
00846       // Node services
00847 
00848       char *Session::getNodeType(CORBA::ULong ni)
00849       {
00850         if(!ni) throw x3d::sai::InvalidNodeException();
00851         try
00852         {
00853           return CORBA::string_dup(id2node(ni)->getType()->getName().c_str());
00854         }
00855         catch(IllegalNodeIdException &)
00856         {
00857           throw x3d::sai::InvalidNodeException();
00858         }
00859       }
00860 
00861       CORBA::ULong Session::getField(CORBA::ULong ni, const char *n)
00862       {
00863         if(!ni) throw x3d::sai::InvalidNodeException();
00864         try
00865         {
00866           const FieldBase *f = id2node(ni)->lookupField(n);
00867           if(!f) throw x3d::sai::InvalidNameException();
00868           return f->getId();
00869         }
00870         catch(IllegalNodeIdException &)
00871         {
00872           throw x3d::sai::InvalidNodeException();
00873         }
00874       }
00875 
00876       void Session::disposeNode(CORBA::ULong ni)
00877       {
00878         nodeMap.remove(ni);
00879       }
00880 
00881 
00882       // Field services
00883 
00884       CORBA::ULong Session::getFieldType(CORBA::ULong ni, CORBA::ULong fi)
00885       {
00886         try
00887         {
00888           Ref<NodeBase> n = id2node(ni);
00889           if(!n) throw x3d::sai::InvalidNodeException();
00890           const FieldBase *f = FieldBase::fetch(fi, n.get());
00891           if(!f) throw x3d::sai::InvalidFieldException();
00892           return f->getType()->getIndex();
00893         }
00894         catch(IllegalNodeIdException &)
00895         {
00896           throw x3d::sai::InvalidNodeException();
00897         }
00898       }
00899 
00900       char *Session::getFieldName(CORBA::ULong ni, CORBA::ULong fi)
00901       {
00902         try
00903         {
00904           Ref<NodeBase> n = id2node(ni);
00905           if(!n) throw x3d::sai::InvalidNodeException();
00906           const FieldBase *f = FieldBase::fetch(fi, n.get());
00907           if(!f) throw x3d::sai::InvalidFieldException();
00908           return CORBA::string_dup(f->getName().c_str());
00909         }
00910         catch(IllegalNodeIdException &)
00911         {
00912           throw x3d::sai::InvalidNodeException();
00913         }
00914       }
00915 
00916       CORBA::ULong Session::getFieldAccessType(CORBA::ULong ni, CORBA::ULong fi)
00917       {
00918         try
00919         {
00920           Ref<NodeBase> n = id2node(ni);
00921           if(!n) throw x3d::sai::InvalidNodeException();
00922           const FieldBase *f = FieldBase::fetch(fi, n.get());
00923           if(!f) throw x3d::sai::InvalidFieldException();
00924           return
00925             f->getIsEventSource() ?
00926             f->getIsEventTarget() ? 3 : 2 :
00927             f->getIsEventTarget() ? 1 : 0;
00928         }
00929         catch(IllegalNodeIdException &)
00930         {
00931           throw x3d::sai::InvalidNodeException();
00932         }
00933       }
00934 
00935       void Session::registerFieldInterest(CORBA::ULong ni, CORBA::ULong fi,
00936                                           CORBA::ULong c)
00937       {
00938         try
00939         {
00940           Ref<NodeBase> n = id2node(ni);
00941           if(!n) throw x3d::sai::InvalidNodeException();
00942           const FieldBase *f = FieldBase::fetch(fi, n.get());
00943           if(!f) throw x3d::sai::InvalidFieldException();
00944 
00945           // Field input/output capabilities
00946           if(!f->getIsEventSource())
00947             throw x3d::sai::InvalidAccessTypeException();
00948 
00949           ExternalRoute::add(n, f, this, c);
00950         }
00951         catch(IllegalNodeIdException &)
00952         {
00953           throw x3d::sai::InvalidNodeException();
00954         }
00955       }
00956 
00963       void Session::unRegisterFieldInterest(CORBA::ULong ni, CORBA::ULong fi,
00964                                             CORBA::ULong c)
00965       {
00966         try
00967         {
00968           Ref<NodeBase> n = id2node(ni);
00969           if(!n) throw x3d::sai::InvalidNodeException();
00970           const FieldBase *f = FieldBase::fetch(fi, n.get());
00971           if(!f) throw x3d::sai::InvalidFieldException();
00972 
00973           // Field input/output capabilities
00974           if(!f->getIsEventSource())
00975             throw x3d::sai::InvalidAccessTypeException();
00976 
00977           ExternalRoute::del(n, f, this, c);
00978           externalEventQueue->flush();
00979         }
00980         catch(IllegalNodeIdException &)
00981         {
00982           throw x3d::sai::InvalidNodeException();
00983         }
00984       }
00985 
00986       x3d::sai::Value *Session::getFieldValue(CORBA::ULong ni, CORBA::ULong fi)
00987       {
00988         try
00989         {
00990           Ref<NodeBase> n = id2node(ni);
00991           if(!n) throw x3d::sai::InvalidNodeException();
00992           const FieldBase *f = FieldBase::fetch(fi, n.get());
00993           if(!f) throw x3d::sai::InvalidFieldException();
00994           if(!f->getIsEventSource() && f->getIsEventTarget())
00995             throw x3d::sai::InvalidAccessTypeException();
00996           Ref<ValueBase> v = n->get(f);
00997           x3d::sai::Value_var w = new x3d::sai::Value();
00998           ex(v.get(), w.inout());
00999           return w._retn();
01000         }
01001         catch(IllegalNodeIdException &)
01002         {
01003           throw x3d::sai::InvalidNodeException();
01004         }
01005         catch(NodeBase::AccessException &)
01006         {
01007           throw x3d::sai::InvalidOperationTimingException();
01008         }
01009       }
01010 
01017       void Session::setFieldValue(CORBA::ULong ni, CORBA::ULong fi,
01018                                   const x3d::sai::Value &v)
01019       {
01020         try
01021         {
01022           Ref<NodeBase> n = id2node(ni);
01023           if(!n) throw x3d::sai::InvalidNodeException();
01024           const FieldBase *f = FieldBase::fetch(fi, n.get());
01025           if(!f) throw x3d::sai::InvalidFieldException();
01026           if(f->getIsEventSource() && !f->getIsEventTarget())
01027             throw x3d::sai::InvalidAccessTypeException();
01028           Ref<ValueBase> w = im(v);
01029           if(w->getFieldType() != f->getType())
01030             throw x3d::sai::InvalidValueException();
01031 
01032           // If the value consists of one or more nodes then verify them
01033           if(const NodeValue *nv = dynamic_cast<const NodeValue *>(w.get()))
01034           {
01035             if(nv->value && nv->value->context != n->context)
01036               throw x3d::sai::InvalidValueException();
01037           }
01038           else if(const NodeSequenceValue *nv =
01039                   dynamic_cast<const NodeSequenceValue *>(w.get()))
01040             for(NodeSequenceValue::ConstIterator i=nv->begin(); i!=nv->end(); ++i)
01041             {
01042               if(!*i || (*i)->context != n->context)
01043                 throw x3d::sai::InvalidValueException();
01044             }
01045 
01046           handleChange(new FieldSetChange(n, f, w));
01047         }
01048         catch(TypeMismatchException &)
01049         {
01050           throw x3d::sai::InvalidValueException();
01051         }
01052         catch(IllegalNodeIdException &)
01053         {
01054           throw x3d::sai::InvalidNodeException();
01055         }
01056         catch(NodeBase::AccessException &)
01057         {
01058           throw x3d::sai::InvalidOperationTimingException();
01059         }
01060       }
01061 
01062 
01063       // SequenceField services
01064 
01065       x3d::sai::Value *Session::getFieldValueAt(CORBA::ULong ni,
01066                                                 CORBA::ULong fi,
01067                                                 CORBA::ULong i)
01068       {
01069         try
01070         {
01071           Ref<NodeBase> n = id2node(ni);
01072           if(!n) throw x3d::sai::InvalidNodeException();
01073           const FieldBase *f = FieldBase::fetch(fi, n.get());
01074           if(!f) throw x3d::sai::InvalidFieldException();
01075           if(!f->getIsEventSource() && f->getIsEventTarget())
01076             throw x3d::sai::InvalidAccessTypeException();
01077           const SequenceFieldBase *s =
01078             dynamic_cast<const SequenceFieldBase *>(f);
01079           if(!s) throw x3d::sai::InvalidAccessTypeException();
01080           Ref<ValueBase> v = n->getAt(s, i);
01081           x3d::sai::Value_var w = new x3d::sai::Value();
01082           ex(v.get(), w.inout());
01083           return w._retn();
01084         }
01085         catch(IllegalNodeIdException &)
01086         {
01087           throw x3d::sai::InvalidNodeException();
01088         }
01089         catch(NodeBase::AccessException &)
01090         {
01091           throw x3d::sai::InvalidOperationTimingException();
01092         }
01093         catch(NodeBase::RangeException &)
01094         {
01095           throw x3d::sai::InvalidIndexException();
01096         }
01097       }
01098 
01105       void Session::setFieldValueAt(CORBA::ULong ni, CORBA::ULong fi,
01106                                     CORBA::ULong i, const x3d::sai::Value &v)
01107       {
01108         try
01109         {
01110           Ref<NodeBase> n = id2node(ni);
01111           if(!n) throw x3d::sai::InvalidNodeException();
01112           const FieldBase *f = FieldBase::fetch(fi, n.get());
01113           if(!f) throw x3d::sai::InvalidFieldException();
01114           if(f->getIsEventSource() != f->getIsEventTarget())
01115             throw x3d::sai::InvalidAccessTypeException();
01116           const SequenceFieldBase *s =
01117             dynamic_cast<const SequenceFieldBase *>(f);
01118           if(!s) throw x3d::sai::InvalidAccessTypeException();
01119           Ref<ValueBase> w = im(v);
01120           if(w->getFieldType() != f->getType()->getSingleType())
01121             throw x3d::sai::InvalidValueException();
01122 
01123           // If the value is a node then verify it
01124           if(const NodeValue *nv = dynamic_cast<const NodeValue *>(w.get()))
01125           {
01126             if(!nv->value || nv->value->context != n->context)
01127               throw x3d::sai::InvalidValueException();
01128           }
01129 
01130           handleChange(new FieldSetAtChange(n, s, w, i));
01131         }
01132         catch(TypeMismatchException &)
01133         {
01134           throw x3d::sai::InvalidValueException();
01135         }
01136         catch(IllegalNodeIdException &)
01137         {
01138           throw x3d::sai::InvalidNodeException();
01139         }
01140         catch(NodeBase::AccessException &)
01141         {
01142           throw x3d::sai::InvalidOperationTimingException();
01143         }
01144         catch(NodeBase::RangeException &)
01145         {
01146           throw x3d::sai::InvalidIndexException();
01147         }
01148       }
01149 
01156       void Session::setFieldValueAdd(CORBA::ULong ni, CORBA::ULong fi,
01157                                      const x3d::sai::Value &v)
01158       {
01159         try
01160         {
01161           Ref<NodeBase> n = id2node(ni);
01162           if(!n) throw x3d::sai::InvalidNodeException();
01163           const FieldBase *f = FieldBase::fetch(fi, n.get());
01164           if(!f) throw x3d::sai::InvalidFieldException();
01165           if(f->getIsEventSource() != f->getIsEventTarget())
01166             throw x3d::sai::InvalidAccessTypeException();
01167           const SequenceFieldBase *s =
01168             dynamic_cast<const SequenceFieldBase *>(f);
01169           if(!s) throw x3d::sai::InvalidAccessTypeException();
01170           Ref<ValueBase> w = im(v);
01171           if(w->getFieldType() != f->getType()->getSingleType())
01172             throw x3d::sai::InvalidValueException();
01173 
01174           // If the value is a node then verify it
01175           if(const NodeValue *nv = dynamic_cast<const NodeValue *>(w.get()))
01176           {
01177             if(!nv->value || nv->value->context != n->context)
01178               throw x3d::sai::InvalidValueException();
01179           }
01180 
01181           handleChange(new FieldListChange(n, s, w));
01182         }
01183         catch(TypeMismatchException &)
01184         {
01185           throw x3d::sai::InvalidValueException();
01186         }
01187         catch(IllegalNodeIdException &)
01188         {
01189           throw x3d::sai::InvalidNodeException();
01190         }
01191         catch(NodeBase::AccessException &)
01192         {
01193           throw x3d::sai::InvalidOperationTimingException();
01194         }
01195       }
01196 
01203       void Session::setFieldValueDel(CORBA::ULong ni, CORBA::ULong fi,
01204                                      const x3d::sai::Value &v)
01205       {
01206         try
01207         {
01208           Ref<NodeBase> n = id2node(ni);
01209           if(!n) throw x3d::sai::InvalidNodeException();
01210           const FieldBase *f = FieldBase::fetch(fi, n.get());
01211           if(!f) throw x3d::sai::InvalidFieldException();
01212           if(f->getIsEventSource() != f->getIsEventTarget())
01213             throw x3d::sai::InvalidAccessTypeException();
01214           const SequenceFieldBase *s =
01215             dynamic_cast<const SequenceFieldBase *>(f);
01216           if(!s) throw x3d::sai::InvalidAccessTypeException();
01217           Ref<ValueBase> w = im(v);
01218           if(w->getFieldType() != f->getType()->getSingleType())
01219             throw x3d::sai::InvalidValueException();
01220 
01221           // If the value is a node then verify it
01222           if(const NodeValue *nv = dynamic_cast<const NodeValue *>(w.get()))
01223           {
01224             if(!nv->value || nv->value->context != n->context)
01225               throw x3d::sai::InvalidValueException();
01226           }
01227 
01228           handleChange(new FieldListChange(n, s, w, true));
01229         }
01230         catch(TypeMismatchException &)
01231         {
01232           throw x3d::sai::InvalidValueException();
01233         }
01234         catch(IllegalNodeIdException &)
01235         {
01236           throw x3d::sai::InvalidNodeException();
01237         }
01238         catch(NodeBase::AccessException &)
01239         {
01240           throw x3d::sai::InvalidOperationTimingException();
01241         }
01242       }
01243 
01244 
01245       void Session::handleChange(Ref<const ChangeBase> c)
01246       {
01247         Mutex::Lock lock(mutex);
01248         if(buffered || !synchronizedChanges)
01249         {
01250           changeQueue.push(c);
01251           if(!buffered) executeChanges();
01252           return;
01253         }
01254         Time time = listener->server->getNextTimeStamp();
01255         c->apply(time);
01256       }
01257 
01258       void Session::handleExternalEvent(const ValueBase *v,
01259                                         unsigned long cookie)
01260       {
01261         externalEventQueue->addEvent(v, cookie);
01262       }
01263 
01264       void Session::addRouteHead(Ref<const ExternalRouteHead> r)
01265       {
01266         Mutex::Lock l(routeHeadsMutex);
01267         routeHeads.push_back(r);
01268       }
01269 
01270       void Session::removeRouteHead(Ref<const ExternalRouteHead> r)
01271       {
01272         Mutex::Lock l(routeHeadsMutex);
01273         routeHeads.remove(r);
01274       }
01275 
01276 
01277 
01278       Session::ExternalEventQueue::ExternalEventQueue
01279       (Ref<Session> session, Time heartbeat):
01280         session(session), heartbeat(heartbeat), nonEmpty(mutex),
01281         hasTerminated(false), flushRequest(false), flushing(false),
01282         flushed(mutex)
01283       {
01284       }
01285         
01286       void Session::ExternalEventQueue::main()
01287       {
01288         for(;;)
01289         {
01290           list<ExternalEvent> q;
01291 
01292           try
01293           {
01294             Mutex::Lock l(mutex);
01295             flushing = false;
01296             if(!flushRequest)
01297             {
01298               l.release();
01299               flushed.notifyAll();
01300               l.aquire(mutex);
01301             }
01302             while(eventQueue.empty())
01303               if(nonEmpty.timedWait(Time::now()+heartbeat)) break;
01304             std::swap(q, eventQueue);
01305             flushing = flushRequest;
01306             flushRequest = false;
01307           }
01308           catch(ThreadTerminatedException &) { break; }
01309 
01310           try { session->pushEvents(&q); }
01311           catch(ForwardDestroyedException &) { break; }
01312         }
01313 
01314         {
01315           Mutex::Lock l(mutex);
01316           hasTerminated = true;
01317           flushRequest = flushing = false;
01318         }
01319         flushed.notifyAll();
01320       }
01321 
01322       void Session::ExternalEventQueue::addEvent(const ValueBase *v,
01323                                                  unsigned long cookie)
01324       {
01325         Mutex::Lock l(mutex);
01326         if(hasTerminated) return;
01327         eventQueue.push_back(ExternalEvent(v, cookie));
01328         nonEmpty.notifyAll();
01329       }
01330 
01331       void Session::ExternalEventQueue::flush()
01332       {
01333         Mutex::Lock l(mutex);
01334         if(hasTerminated) return;
01335         flushRequest = true;
01336         while(flushRequest || flushing) flushed.wait();
01337       }
01338 
01339 
01340       void Session::pushEvents(const list<ExternalEvent> *q)
01341       {
01342         unsigned long n = q->size();
01343         x3d::sai::EventSeq s(n);
01344         s.length(n);
01345         unsigned j = 0;
01346         list<ExternalEvent>::const_iterator i = q->begin();
01347         while(i != q->end())
01348         {
01349           x3d::sai::Event &e = s[j++];
01350           e.cookie = i->cookie;
01351           ex(i->value.get(), e.val);
01352           ++i;
01353         }
01354         try { application->handleEvent(s); }
01355         catch(...)
01356         {
01357           disposeSession();
01358           return;
01359         }
01360       }
01361 
01362 
01363       Ref<Stream::Reader> Session::request(string p)
01364         throw(AbstractFileServer::RequestException)
01365       {
01366         x3d::sai::StreamReader_var r;
01367         try { r = application->requestFile(p.c_str()); }
01368         catch(x3d::sai::FileRequestException &e)
01369         {
01370           ARCHON_THROW1(AbstractFileServer::RequestException, string(e.message));
01371         }
01372         catch(...)
01373         {
01374           ARCHON_THROW1(AbstractFileServer::RequestException,
01375                         "Caught unknown exception");
01376         }
01377         if(CORBA::is_nil(r))
01378           ARCHON_THROW1(AbstractFileServer::RequestException,
01379                         "Got nil reader");
01380         return new Reader(r);
01381       }
01382 
01383       void Session::log(string s) throw()
01384       {
01385         try { application->log(s.c_str()); }
01386         catch(...) {}
01387       }
01388     }
01389   }
01390 }

Generated on Sun Jul 30 22:55:48 2006 for Archon by  doxygen 1.4.4