00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
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
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
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
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
00400
00401
00402
00403
00404
00405
00406 externalEventQueue->terminate();
00407 externalEventQueue.reset();
00408
00409 deactivate();
00410 nodeMap.clear();
00411 contextMap.clear();
00412 routeHeads.clear();
00413
00414
00415
00416
00417
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
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
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
00639 deactivate();
00640
00641
00642
00643
00644 try { listener->removeSession(this); }
00645 catch(ForwardDestroyedException &) {}
00646 }
00647
00648
00649
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
00749 if(!sourceField->getIsEventSource() ||
00750 !targetField->getIsEventTarget())
00751 throw x3d::sai::InvalidAccessTypeException();
00752
00753
00754 if(sourceField->getType() != targetField->getType())
00755 throw x3d::sai::InvalidAccessTypeException();
00756
00757
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
00796 if(!sourceField->getIsEventSource() ||
00797 !targetField->getIsEventTarget())
00798 throw x3d::sai::InvalidAccessTypeException();
00799
00800
00801 if(sourceField->getType() != targetField->getType())
00802 throw x3d::sai::InvalidAccessTypeException();
00803
00804
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
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
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
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
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
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
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
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
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
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 }