#ifndef _QmfEngineBrokerProxyImpl_ #define _QmfEngineBrokerProxyImpl_ /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include "qmf/engine/Console.h" #include "qmf/engine/ObjectImpl.h" #include "qmf/engine/EventImpl.h" #include "qmf/engine/SchemaImpl.h" #include "qmf/engine/ValueImpl.h" #include "qmf/engine/QueryImpl.h" #include "qmf/engine/SequenceManager.h" #include "qmf/engine/MessageImpl.h" #include "qpid/framing/Buffer.h" #include "qpid/framing/Uuid.h" #include "qpid/sys/Mutex.h" #include "boost/shared_ptr.hpp" #include "boost/noncopyable.hpp" #include #include #include #include #include #include namespace qmf { namespace engine { typedef boost::shared_ptr MethodResponsePtr; struct MethodResponseImpl { uint32_t status; const SchemaMethod* schema; std::auto_ptr exception; std::auto_ptr arguments; MethodResponseImpl(const MethodResponseImpl& from); MethodResponseImpl(qpid::framing::Buffer& buf, const SchemaMethod* schema); MethodResponseImpl(uint32_t status, const std::string& text); static MethodResponse* factory(qpid::framing::Buffer& buf, const SchemaMethod* schema); static MethodResponse* factory(uint32_t status, const std::string& text); ~MethodResponseImpl() {} uint32_t getStatus() const { return status; } const Value* getException() const { return exception.get(); } const Value* getArgs() const { return arguments.get(); } }; typedef boost::shared_ptr QueryResponsePtr; struct QueryResponseImpl { uint32_t status; std::auto_ptr exception; std::vector results; QueryResponseImpl() : status(0) {} static QueryResponse* factory() { QueryResponseImpl* impl(new QueryResponseImpl()); return new QueryResponse(impl); } ~QueryResponseImpl() {} uint32_t getStatus() const { return status; } const Value* getException() const { return exception.get(); } uint32_t getObjectCount() const { return results.size(); } const Object* getObject(uint32_t idx) const; }; struct BrokerEventImpl { typedef boost::shared_ptr Ptr; BrokerEvent::EventKind kind; std::string name; std::string exchange; std::string bindingKey; void* context; QueryResponsePtr queryResponse; MethodResponsePtr methodResponse; BrokerEventImpl(BrokerEvent::EventKind k) : kind(k), context(0) {} ~BrokerEventImpl() {} BrokerEvent copy(); }; typedef boost::shared_ptr AgentProxyPtr; struct AgentProxyImpl { Console& console; BrokerProxy& broker; uint32_t agentBank; std::string label; std::set inFlightSequences; AgentProxyImpl(Console& c, BrokerProxy& b, uint32_t ab, const std::string& l) : console(c), broker(b), agentBank(ab), label(l) {} static AgentProxy* factory(Console& c, BrokerProxy& b, uint32_t ab, const std::string& l) { AgentProxyImpl* impl(new AgentProxyImpl(c, b, ab, l)); return new AgentProxy(impl); } ~AgentProxyImpl() {} const std::string& getLabel() const { return label; } uint32_t getBrokerBank() const { return 1; } uint32_t getAgentBank() const { return agentBank; } void addSequence(uint32_t seq) { inFlightSequences.insert(seq); } void delSequence(uint32_t seq) { inFlightSequences.erase(seq); } void releaseInFlight(SequenceManager& seqMgr) { for (std::set::iterator iter = inFlightSequences.begin(); iter != inFlightSequences.end(); iter++) seqMgr.release(*iter); inFlightSequences.clear(); } }; class BrokerProxyImpl : public boost::noncopyable { public: BrokerProxyImpl(BrokerProxy& pub, Console& _console); ~BrokerProxyImpl() {} void sessionOpened(SessionHandle& sh); void sessionClosed(); void startProtocol(); void sendBufferLH(qpid::framing::Buffer& buf, const std::string& destination, const std::string& routingKey); void handleRcvMessage(Message& message); bool getXmtMessage(Message& item) const; void popXmt(); bool getEvent(BrokerEvent& event) const; void popEvent(); uint32_t agentCount() const; const AgentProxy* getAgent(uint32_t idx) const; void sendQuery(const Query& query, void* context, const AgentProxy* agent); bool sendGetRequestLH(SequenceContext::Ptr queryContext, const Query& query, const AgentProxy* agent); std::string encodeMethodArguments(const SchemaMethod* schema, const Value* args, qpid::framing::Buffer& buffer); std::string encodedSizeMethodArguments(const SchemaMethod* schema, const Value* args, uint32_t& size); void sendMethodRequest(ObjectId* oid, const SchemaObjectClass* cls, const std::string& method, const Value* args, void* context); void addBinding(const std::string& exchange, const std::string& key); void staticRelease() { decOutstanding(); } private: friend struct StaticContext; friend struct QueryContext; friend struct MethodContext; BrokerProxy& publicObject; mutable qpid::sys::Mutex lock; Console& console; std::string queueName; qpid::framing::Uuid brokerId; SequenceManager seqMgr; uint32_t requestsOutstanding; bool topicBound; std::map agentList; std::deque xmtQueue; std::deque eventQueue; # define MA_BUFFER_SIZE 65536 char outputBuffer[MA_BUFFER_SIZE]; BrokerEventImpl::Ptr eventDeclareQueue(const std::string& queueName); BrokerEventImpl::Ptr eventBind(const std::string& exchange, const std::string& queue, const std::string& key); BrokerEventImpl::Ptr eventSetupComplete(); BrokerEventImpl::Ptr eventStable(); BrokerEventImpl::Ptr eventQueryComplete(void* context, QueryResponsePtr response); BrokerEventImpl::Ptr eventMethodResponse(void* context, MethodResponsePtr response); void handleBrokerResponse(qpid::framing::Buffer& inBuffer, uint32_t seq); void handlePackageIndication(qpid::framing::Buffer& inBuffer, uint32_t seq); void handleCommandComplete(qpid::framing::Buffer& inBuffer, uint32_t seq); void handleClassIndication(qpid::framing::Buffer& inBuffer, uint32_t seq); MethodResponsePtr handleMethodResponse(qpid::framing::Buffer& inBuffer, uint32_t seq, const SchemaMethod* schema); void handleHeartbeatIndication(qpid::framing::Buffer& inBuffer, uint32_t seq, const std::string& routingKey); void handleEventIndication(qpid::framing::Buffer& inBuffer, uint32_t seq); void handleSchemaResponse(qpid::framing::Buffer& inBuffer, uint32_t seq); ObjectPtr handleObjectIndication(qpid::framing::Buffer& inBuffer, uint32_t seq, bool prop, bool stat); void updateAgentList(ObjectPtr obj); void incOutstandingLH(); void decOutstanding(); }; // // StaticContext is used to handle: // // 1) Responses to console-level requests (for schema info, etc.) // 2) Unsolicited messages from agents (events, published updates, etc.) // struct StaticContext : public SequenceContext { StaticContext(BrokerProxyImpl& b) : broker(b) {} virtual ~StaticContext() {} void reserve() {} void release() { broker.staticRelease(); } bool handleMessage(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer); BrokerProxyImpl& broker; }; // // QueryContext is used to track and handle responses associated with a single Get Query // struct QueryContext : public SequenceContext { QueryContext(BrokerProxyImpl& b, void* u) : broker(b), userContext(u), requestsOutstanding(0), queryResponse(QueryResponseImpl::factory()) {} virtual ~QueryContext() {} void reserve(); void release(); bool handleMessage(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer); mutable qpid::sys::Mutex lock; BrokerProxyImpl& broker; void* userContext; uint32_t requestsOutstanding; QueryResponsePtr queryResponse; }; struct MethodContext : public SequenceContext { MethodContext(BrokerProxyImpl& b, void* u, const SchemaMethod* s) : broker(b), userContext(u), schema(s) {} virtual ~MethodContext() {} void reserve() {} void release(); bool handleMessage(uint8_t opcode, uint32_t sequence, const std::string& routingKey, qpid::framing::Buffer& buffer); BrokerProxyImpl& broker; void* userContext; const SchemaMethod* schema; MethodResponsePtr methodResponse; }; } } #endif