Files
ThirdParty-6/ParaView-5.0.1/ParaViewCore/ServerImplementation/Core/vtkSIProxy.cxx

600 lines
18 KiB
C++

/*=========================================================================
Program: ParaView
Module: vtkSIProxy.cxx
Copyright (c) Kitware, Inc.
All rights reserved.
See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkSIProxy.h"
#include "vtkAlgorithm.h"
#include "vtkAlgorithmOutput.h"
#include "vtkClientServerInterpreter.h"
#include "vtkClientServerStream.h"
#include "vtkObjectFactory.h"
#include "vtkPVInstantiator.h"
#include "vtkPVSessionCore.h"
#include "vtkPVXMLElement.h"
#include "vtkSIProperty.h"
#include "vtkSIProxyDefinitionManager.h"
#include "vtkSmartPointer.h"
#include "vtkSMMessage.h"
#include <map>
#include <set>
#include <string>
#include <sstream>
//****************************************************************************
struct SubProxyInfo
{
SubProxyInfo(std::string name, vtkTypeUInt32 id)
{
this->Name = name;
this->GlobalID = id;
}
std::string Name;
vtkTypeUInt32 GlobalID;
};
//****************************************************************************
class vtkSIProxy::vtkInternals
{
public:
void ClearDependencies()
{
this->SIProperties.clear();
this->SubSIProxies.clear();
}
typedef std::map<std::string, vtkSmartPointer<vtkSIProperty> >
SIPropertiesMapType;
SIPropertiesMapType SIProperties;
typedef std::map<std::string, vtkSmartPointer<vtkSIProxy> >
SubSIProxiesMapType;
SubSIProxiesMapType SubSIProxies;
typedef std::vector<SubProxyInfo> SubProxiesVectorType;
SubProxiesVectorType SubProxyInfoVector;
typedef std::map<std::string, std::string> SubProxyCommandMapType;
SubProxyCommandMapType SubProxyCommands;
};
//****************************************************************************
vtkStandardNewMacro(vtkSIProxy);
//----------------------------------------------------------------------------
vtkSIProxy::vtkSIProxy()
{
this->Internals = new vtkInternals();
this->VTKObject = NULL;
this->ObjectsCreated = false;
this->XMLGroup = 0;
this->XMLName = 0;
this->XMLSubProxyName = 0;
this->VTKClassName = 0;
this->PostPush = 0;
this->PostCreation = 0;
}
//----------------------------------------------------------------------------
vtkSIProxy::~vtkSIProxy()
{
this->DeleteVTKObjects();
delete this->Internals;
this->Internals = 0;
this->SetXMLGroup(0);
this->SetXMLName(0);
this->SetXMLSubProxyName(0);
this->SetVTKClassName(0);
this->SetPostPush(0);
this->SetPostCreation(0);
}
//----------------------------------------------------------------------------
void vtkSIProxy::SetVTKObject(vtkObjectBase* obj)
{
this->VTKObject = obj;
}
//----------------------------------------------------------------------------
void vtkSIProxy::Push(vtkSMMessage* message)
{
if (!this->CreateVTKObjects(message))
{
return;
}
// Handle properties
int cc = 0;
int size = message->ExtensionSize(ProxyState::property);
for (;cc < size; cc++)
{
const ProxyState_Property &propMsg =
message->GetExtension(ProxyState::property, cc);
// Convert state to interpretor stream
vtkSIProperty* prop = this->GetSIProperty(propMsg.name().c_str());
if (prop)
{
if (prop->Push(message, cc) == false)
{
vtkErrorMacro("Error pushing property state: " << propMsg.name());
message->PrintDebugString();
return;
}
}
}
// Execute post_push if any
if(this->PostPush != NULL)
{
vtkClientServerStream stream;
stream << vtkClientServerStream::Invoke
<< this->GetVTKObject()
<< this->PostPush
<< vtkClientServerStream::End;
this->Interpreter->ProcessStream(stream);
}
}
//----------------------------------------------------------------------------
void vtkSIProxy::Pull(vtkSMMessage* message)
{
if (!this->ObjectsCreated)
{
return;
}
// Return a set of Pull only property (information_only props)
// In fact Pushed Property can not be fetch at the same time as Pull
// property with the current implementation
std::set<std::string> prop_names;
if (message->ExtensionSize(PullRequest::arguments) > 0)
{
const Variant *propList = &message->GetExtension(PullRequest::arguments, 0);
for(int i=0; i < propList->txt_size(); ++i)
{
const char* propertyName = propList->txt(i).c_str();
prop_names.insert(propertyName);
}
}
message->ClearExtension(PullRequest::arguments);
vtkInternals::SIPropertiesMapType::iterator iter;
for (iter = this->Internals->SIProperties.begin(); iter !=
this->Internals->SIProperties.end(); ++iter)
{
if (prop_names.size() == 0 ||
prop_names.find(iter->first) != prop_names.end())
{
if(!iter->second->GetIsInternal())
{
if(message->req_def())
{
// We just want the cached push property
if( !iter->second->GetInformationOnly() &&
!iter->second->Pull(message))
{
vtkErrorMacro("Error pulling property state: " << iter->first);
return;
}
}
else if (!iter->second->Pull(message))
{
vtkErrorMacro("Error pulling property state: " << iter->first);
return;
}
}
}
}
if(message->req_def())
{
// Add definition
message->SetExtension(ProxyState::xml_group, this->XMLGroup);
message->SetExtension(ProxyState::xml_name, this->XMLName);
if(this->XMLSubProxyName)
{
message->SetExtension(ProxyState::xml_sub_proxy_name, this->XMLSubProxyName);
}
// Add subproxy information to the message.
vtkInternals::SubProxiesVectorType::iterator it2 =
this->Internals->SubProxyInfoVector.begin();
for( ; it2 != this->Internals->SubProxyInfoVector.end(); it2++)
{
ProxyState_SubProxy *subproxy = message->AddExtension(ProxyState::subproxy);
subproxy->set_name(it2->Name.c_str());
subproxy->set_global_id(it2->GlobalID);
}
}
}
//----------------------------------------------------------------------------
vtkSIProxyDefinitionManager* vtkSIProxy::GetProxyDefinitionManager()
{
if (this->SessionCore)
{
return this->SessionCore->GetProxyDefinitionManager();
}
vtkWarningMacro("No valid session provided. "
"This class may not have been initialized yet.");
return NULL;
}
//----------------------------------------------------------------------------
vtkSIProperty* vtkSIProxy::GetSIProperty(const char* name)
{
vtkInternals::SIPropertiesMapType::iterator iter =
this->Internals->SIProperties.find(name);
if (iter != this->Internals->SIProperties.end())
{
return iter->second.GetPointer();
}
return NULL;
}
//----------------------------------------------------------------------------
void vtkSIProxy::AddSIProperty(const char* name, vtkSIProperty* property)
{
this->Internals->SIProperties[name] = property;
}
//----------------------------------------------------------------------------
bool vtkSIProxy::CreateVTKObjects(vtkSMMessage* message)
{
if (this->ObjectsCreated)
{
return true;
}
if (!message->HasExtension(ProxyState::xml_group) ||
!message->HasExtension(ProxyState::xml_name))
{
vtkErrorMacro("Incorrect message received. "
<< "Missing xml_group and xml_name information." << endl
<< message->DebugString().c_str() << endl);
return false;
}
// Store definition informations
this->SetXMLGroup(message->GetExtension(ProxyState::xml_group).c_str());
this->SetXMLName(message->GetExtension(ProxyState::xml_name).c_str());
this->SetXMLSubProxyName(
message->HasExtension(ProxyState::xml_sub_proxy_name) ?
message->GetExtension(ProxyState::xml_sub_proxy_name).c_str() : NULL);
vtkSIProxyDefinitionManager* pdm = this->GetProxyDefinitionManager();
vtkPVXMLElement* element = pdm->GetCollapsedProxyDefinition(
message->GetExtension(ProxyState::xml_group).c_str(),
message->GetExtension(ProxyState::xml_name).c_str(),
(message->HasExtension(ProxyState::xml_sub_proxy_name) ?
message->GetExtension(ProxyState::xml_sub_proxy_name).c_str() :
NULL));
if (!element)
{
vtkErrorMacro("Definition not found for xml_group: "
<< message->GetExtension(ProxyState::xml_group).c_str()
<< " and xml_name: "
<< message->GetExtension(ProxyState::xml_name).c_str()
<< endl << message->DebugString().c_str() << endl );
return false;
}
// Create and setup the VTK object, if needed before parsing the property
// helpers. This is needed so that the property helpers can push their default
// values as they are reading the xml-attributes.
const char* className = element->GetAttribute("class");
if (className && className[0])
{
this->SetVTKClassName(className);
vtkObjectBase* obj = this->Interpreter->NewInstance(className);
if (!obj)
{
vtkErrorMacro("Failed to create " << className
<< ". Aborting for debugging purposes.");
abort();
}
this->VTKObject.TakeReference(obj);
}
if (this->VTKClassName && this->VTKClassName[0] != '\0')
{
vtkClientServerStream substream;
substream << vtkClientServerStream::Invoke
<< vtkClientServerID(1)
<< "GetActiveProgressHandler"
<< vtkClientServerStream::End;
vtkClientServerStream stream;
stream << vtkClientServerStream::Invoke
<< substream
<< "RegisterProgressEvent"
<< this->VTKObject
<< static_cast<int>(this->GetGlobalID())
<< vtkClientServerStream::End;
this->Interpreter->ProcessStream(stream);
}
this->SetXMLGroup(message->GetExtension(ProxyState::xml_group).c_str());
this->SetXMLName(message->GetExtension(ProxyState::xml_name).c_str());
// Locate sub-proxies.
for (int cc=0; cc < message->ExtensionSize(ProxyState::subproxy); cc++)
{
const ProxyState_SubProxy& subproxyMsg =
message->GetExtension(ProxyState::subproxy, cc);
vtkSIProxy* subproxy = vtkSIProxy::SafeDownCast(
this->GetSIObject(subproxyMsg.global_id()));
this->Internals->SubProxyInfoVector.push_back(
SubProxyInfo(subproxyMsg.name(), subproxyMsg.global_id()));
if (subproxy == NULL)
{
// This code has been commented to support ImplicitPlaneWidgetRepresentation
// which as a widget as SubProxy which stay on the client side.
// Therefore, when ParaView is running on Client/Server mode, that SubProxy
// does NOT exist on the Server side. This case should not fail the current
// proxy creation.
// vtkErrorMacro("Failed to locate subproxy with global-id: "
// << subproxyMsg.global_id() << endl
// << message->DebugString().c_str());
// return false;
}
else
{
this->Internals->SubSIProxies[subproxyMsg.name()] = subproxy;
}
}
// Add hook for post_push and post_creation. This is processed before
// ReadXMLAttributes() is even called.
this->SetPostPush(element->GetAttribute("post_push"));
this->SetPostCreation(element->GetAttribute("post_creation"));
// Allow subclasses to do some initialization if needed. Note this is called
// before properties are created.
this->OnCreateVTKObjects();
// Execute post-creation if any
if(this->PostCreation != NULL)
{
vtkClientServerStream stream;
stream << vtkClientServerStream::Invoke
<< this->GetVTKObject()
<< this->PostCreation
<< vtkClientServerStream::End;
this->Interpreter->ProcessStream(stream);
}
// Process the XML and update properties etc.
if (!this->ReadXMLAttributes(element))
{
this->DeleteVTKObjects();
return false;
}
this->ObjectsCreated = true;
return true;
}
//----------------------------------------------------------------------------
void vtkSIProxy::DeleteVTKObjects()
{
this->VTKObject = NULL;
}
//----------------------------------------------------------------------------
void vtkSIProxy::OnCreateVTKObjects()
{
}
//----------------------------------------------------------------------------
vtkObjectBase* vtkSIProxy::GetVTKObject()
{
return this->VTKObject.GetPointer();
}
//----------------------------------------------------------------------------
bool vtkSIProxy::ReadXMLAttributes(vtkPVXMLElement* element)
{
for(unsigned int i=0; i < element->GetNumberOfNestedElements(); ++i)
{
vtkPVXMLElement* propElement = element->GetNestedElement(i);
if (strcmp(propElement->GetName(), "SubProxy") == 0)
{
// read subproxy xml.
if (!this->ReadXMLSubProxy(propElement))
{
return false;
}
}
}
// Process sub-proxy commands.
for (vtkInternals::SubProxyCommandMapType::iterator iter=this->Internals->SubProxyCommands.begin();
iter != this->Internals->SubProxyCommands.end(); ++iter)
{
if (vtkSIProxy* subProxy = this->GetSubSIProxy(iter->first.c_str()))
{
vtkClientServerStream stream;
stream << vtkClientServerStream::Invoke
<< this->GetVTKObject()
<< iter->second.c_str()
<< subProxy->GetVTKObject()
<< vtkClientServerStream::End;
this->Interpreter->ProcessStream(stream);
}
}
for (unsigned int i=0; i < element->GetNumberOfNestedElements(); ++i)
{
vtkPVXMLElement* propElement = element->GetNestedElement(i);
// read property xml
const char* name = propElement->GetAttribute("name");
std::string tagName = propElement->GetName();
if (name && tagName.find("Property") == (tagName.size()-8))
{
if (!this->ReadXMLProperty(propElement))
{
return false;
}
}
}
return true;
}
//----------------------------------------------------------------------------
bool vtkSIProxy::ReadXMLSubProxy(vtkPVXMLElement* subproxyElement)
{
// Process "command" for the sub proxy, if any. These are used in
// CreateVTKObjects() to pass the sub proxy's VTK object to this proxy's VTK
// object.
const char* command = subproxyElement? subproxyElement->GetAttribute("command") : NULL;
if (command)
{
vtkPVXMLElement* proxyElement = subproxyElement->GetNestedElement(0);
const char* name = proxyElement? proxyElement->GetAttribute("name") : NULL;
if (name)
{
this->Internals->SubProxyCommands[name] = command;
}
}
return true;
}
//----------------------------------------------------------------------------
bool vtkSIProxy::ReadXMLProperty(vtkPVXMLElement* propElement)
{
// Since the XML is "cleaned" out, we are assured that there are no duplicate
// properties.
std::string name = propElement->GetAttributeOrEmpty("name");
assert(!name.empty() && this->GetSIProperty(name.c_str()) == NULL);
// Patch XML to remove InformationHelper and set right si_class
vtkSIProxyDefinitionManager::PatchXMLProperty(propElement);
vtkSmartPointer<vtkObject> object;
std::string classname;
if (propElement->GetAttribute("si_class"))
{
classname = propElement->GetAttribute("si_class");
}
else
{
std::ostringstream cname;
cname << "vtkSI" << propElement->GetName() << ends;
classname = cname.str();
}
object.TakeReference(vtkPVInstantiator::CreateInstance(classname.c_str()));
if (!object)
{
vtkErrorMacro("Failed to create helper for property: " << classname);
return false;
}
vtkSIProperty* property = vtkSIProperty::SafeDownCast(object);
if (!property)
{
vtkErrorMacro(<< classname << " must be a vtkSIProperty subclass.");
return false;
}
if (!property->ReadXMLAttributes(this, propElement))
{
vtkErrorMacro("Could not parse property: " << name.c_str());
return false;
}
this->AddSIProperty(name.c_str(), property);
return true;
}
//----------------------------------------------------------------------------
vtkSIProxy* vtkSIProxy::GetSubSIProxy(const char* name)
{
return this->Internals->SubSIProxies[name];
}
//----------------------------------------------------------------------------
unsigned int vtkSIProxy::GetNumberOfSubSIProxys()
{
return static_cast<unsigned int>(this->Internals->SubSIProxies.size());
}
//----------------------------------------------------------------------------
vtkSIProxy* vtkSIProxy::GetSubSIProxy(unsigned int cc)
{
if (cc >= this->GetNumberOfSubSIProxys())
{
return NULL;
}
unsigned int index=0;
vtkInternals::SubSIProxiesMapType::iterator iter;
for (iter = this->Internals->SubSIProxies.begin();
iter != this->Internals->SubSIProxies.end();
++iter, ++index)
{
if (index == cc)
{
return iter->second;
}
}
return NULL;
}
//----------------------------------------------------------------------------
void vtkSIProxy::AddInput(
int inputPort, vtkAlgorithmOutput* connection, const char* method)
{
vtkClientServerStream stream;
stream << vtkClientServerStream::Invoke
<< this->GetVTKObject()
<< method;
if (inputPort > 0)
{
stream << inputPort;
}
stream << connection << vtkClientServerStream::End;
this->Interpreter->ProcessStream(stream);
}
//----------------------------------------------------------------------------
void vtkSIProxy::CleanInputs(const char* method)
{
vtkClientServerStream stream;
stream << vtkClientServerStream::Invoke
<< this->GetVTKObject()
<< method
<< vtkClientServerStream::End;
this->Interpreter->ProcessStream(stream);
}
//----------------------------------------------------------------------------
void vtkSIProxy::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
}
//----------------------------------------------------------------------------
void vtkSIProxy::AboutToDelete()
{
// Remove all proxy/input property that still old other SIProxy reference...
this->Internals->ClearDependencies();
}