summaryrefslogtreecommitdiff
path: root/cpp/src/Ice/ProxyFactory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/Ice/ProxyFactory.cpp')
-rw-r--r--cpp/src/Ice/ProxyFactory.cpp300
1 files changed, 300 insertions, 0 deletions
diff --git a/cpp/src/Ice/ProxyFactory.cpp b/cpp/src/Ice/ProxyFactory.cpp
new file mode 100644
index 00000000000..c68b3e35f57
--- /dev/null
+++ b/cpp/src/Ice/ProxyFactory.cpp
@@ -0,0 +1,300 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <IceUtil/Thread.h>
+#include <IceUtil/Time.h>
+#include <Ice/ProxyFactory.h>
+#include <Ice/Instance.h>
+#include <Ice/Proxy.h>
+#include <Ice/ReferenceFactory.h>
+#include <Ice/LocatorInfo.h>
+#include <Ice/RouterInfo.h>
+#include <Ice/BasicStream.h>
+#include <Ice/Properties.h>
+#include <Ice/LoggerUtil.h>
+#include <Ice/TraceLevels.h>
+#include <Ice/LocalException.h>
+#include <Ice/OutgoingAsync.h>
+
+using namespace std;
+using namespace Ice;
+using namespace IceInternal;
+
+IceUtil::Shared* IceInternal::upCast(ProxyFactory* p) { return p; }
+
+ObjectPrx
+IceInternal::ProxyFactory::stringToProxy(const string& str) const
+{
+ ReferencePtr ref = _instance->referenceFactory()->create(str, "");
+ return referenceToProxy(ref);
+}
+
+string
+IceInternal::ProxyFactory::proxyToString(const ObjectPrx& proxy) const
+{
+ if(proxy)
+ {
+ return proxy->__reference()->toString();
+ }
+ else
+ {
+ return "";
+ }
+}
+
+ObjectPrx
+IceInternal::ProxyFactory::propertyToProxy(const string& prefix) const
+{
+ string proxy = _instance->initializationData().properties->getProperty(prefix);
+ ReferencePtr ref = _instance->referenceFactory()->create(proxy, prefix);
+ return referenceToProxy(ref);
+}
+
+PropertyDict
+IceInternal::ProxyFactory::proxyToProperty(const ObjectPrx& proxy, const string& prefix) const
+{
+ if(proxy)
+ {
+ return proxy->__reference()->toProperty(prefix);
+ }
+ else
+ {
+ return PropertyDict();
+ }
+}
+
+ObjectPrx
+IceInternal::ProxyFactory::streamToProxy(BasicStream* s) const
+{
+ Identity ident;
+ ident.__read(s);
+
+ ReferencePtr ref = _instance->referenceFactory()->create(ident, s);
+ return referenceToProxy(ref);
+}
+
+void
+IceInternal::ProxyFactory::proxyToStream(const ObjectPrx& proxy, BasicStream* s) const
+{
+ if(proxy)
+ {
+ proxy->__reference()->getIdentity().__write(s);
+ proxy->__reference()->streamWrite(s);
+ }
+ else
+ {
+ Identity ident;
+ ident.__write(s);
+ }
+}
+
+ObjectPrx
+IceInternal::ProxyFactory::referenceToProxy(const ReferencePtr& ref) const
+{
+ if(ref)
+ {
+ ObjectPrx proxy = new ::IceProxy::Ice::Object;
+ proxy->setup(ref);
+ return proxy;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+int
+IceInternal::ProxyFactory::checkRetryAfterException(const LocalException& ex,
+ const ReferencePtr& ref,
+ bool sleep,
+ int& cnt) const
+{
+ TraceLevelsPtr traceLevels = _instance->traceLevels();
+ LoggerPtr logger = _instance->initializationData().logger;
+
+ //
+ // We don't retry batch requests because the exception might have caused
+ // the all the requests batched with the connection to be aborted and we
+ // want the application to be notified.
+ //
+ if(ref->getMode() == Reference::ModeBatchOneway || ref->getMode() == Reference::ModeBatchDatagram)
+ {
+ ex.ice_throw();
+ }
+
+ const ObjectNotExistException* one = dynamic_cast<const ObjectNotExistException*>(&ex);
+
+ if(one)
+ {
+ if(ref->getRouterInfo() && one->operation == "ice_add_proxy")
+ {
+ //
+ // If we have a router, an ObjectNotExistException with an
+ // operation name "ice_add_proxy" indicates to the client
+ // that the router isn't aware of the proxy (for example,
+ // because it was evicted by the router). In this case, we
+ // must *always* retry, so that the missing proxy is added
+ // to the router.
+ //
+
+ ref->getRouterInfo()->clearCache(ref);
+
+ if(traceLevels->retry >= 1)
+ {
+ Trace out(logger, traceLevels->retryCat);
+ out << "retrying operation call to add proxy to router\n" << ex;
+ }
+
+ return 0; // We must always retry, so we don't look at the retry count.
+ }
+ else if(ref->isIndirect())
+ {
+ //
+ // We retry ObjectNotExistException if the reference is
+ // indirect.
+ //
+
+ if(ref->isWellKnown())
+ {
+ LocatorInfoPtr li = ref->getLocatorInfo();
+ if(li)
+ {
+ li->clearCache(ref);
+ }
+ }
+ }
+ else
+ {
+ //
+ // For all other cases, we don't retry
+ // ObjectNotExistException.
+ //
+ ex.ice_throw();
+ }
+ }
+ else if(dynamic_cast<const RequestFailedException*>(&ex))
+ {
+ //
+ // We don't retry other *NotExistException, which are all
+ // derived from RequestFailedException.
+ //
+ ex.ice_throw();
+ }
+
+ //
+ // There is no point in retrying an operation that resulted in a
+ // MarshalException. This must have been raised locally (because
+ // if it happened in a server it would result in an
+ // UnknownLocalException instead), which means there was a problem
+ // in this process that will not change if we try again.
+ //
+ // The most likely cause for a MarshalException is exceeding the
+ // maximum message size, which is represented by the the subclass
+ // MemoryLimitException. For example, a client can attempt to send
+ // a message that exceeds the maximum memory size, or accumulate
+ // enough batch requests without flushing that the maximum size is
+ // reached.
+ //
+ // This latter case is especially problematic, because if we were
+ // to retry a batch request after a MarshalException, we would in
+ // fact silently discard the accumulated requests and allow new
+ // batch requests to accumulate. If the subsequent batched
+ // requests do not exceed the maximum message size, it appears to
+ // the client that all of the batched requests were accepted, when
+ // in reality only the last few are actually sent.
+ //
+ if(dynamic_cast<const MarshalException*>(&ex))
+ {
+ ex.ice_throw();
+ }
+
+ ++cnt;
+ assert(cnt > 0);
+
+ int interval;
+ if(cnt == static_cast<int>(_retryIntervals.size() + 1) &&
+ dynamic_cast<const CloseConnectionException*>(&ex))
+ {
+ //
+ // A close connection exception is always retried at least once, even if the retry
+ // limit is reached.
+ //
+ interval = 0;
+ }
+ else if(cnt > static_cast<int>(_retryIntervals.size()))
+ {
+ if(traceLevels->retry >= 1)
+ {
+ Trace out(logger, traceLevels->retryCat);
+ out << "cannot retry operation call because retry limit has been exceeded\n" << ex;
+ }
+ ex.ice_throw();
+ }
+ else
+ {
+ interval = _retryIntervals[cnt - 1];
+ }
+
+ if(traceLevels->retry >= 1)
+ {
+ Trace out(logger, traceLevels->retryCat);
+ out << "retrying operation call";
+ if(interval > 0)
+ {
+ out << " in " << interval << "ms";
+ }
+ out << " because of exception\n" << ex;
+ }
+
+ if(sleep && interval > 0)
+ {
+ //
+ // Sleep before retrying.
+ //
+ IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(interval));
+ }
+ return interval;
+}
+
+IceInternal::ProxyFactory::ProxyFactory(const InstancePtr& instance) :
+ _instance(instance)
+{
+ StringSeq retryValues = _instance->initializationData().properties->getPropertyAsList("Ice.RetryIntervals");
+ if(retryValues.size() == 0)
+ {
+ _retryIntervals.push_back(0);
+ }
+ else
+ {
+ for(StringSeq::const_iterator p = retryValues.begin(); p != retryValues.end(); ++p)
+ {
+ istringstream value(*p);
+
+ int v;
+ if(!(value >> v) || !value.eof())
+ {
+ v = 0;
+ }
+
+ //
+ // If -1 is the first value, no retry and wait intervals.
+ //
+ if(v == -1 && _retryIntervals.empty())
+ {
+ break;
+ }
+
+ _retryIntervals.push_back(v > 0 ? v : 0);
+ }
+ }
+}
+
+IceInternal::ProxyFactory::~ProxyFactory()
+{
+}