/* Copyright (C) 2000,2001 Stefan Westerfeld stefan@space.twc.de This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "artsbuilder.h" #include "artsflow.h" #include "connect.h" #include "debug.h" #include "flowsystem.h" #include "stdsynthmodule.h" #include "dynamicrequest.h" #include "dynamicskeleton.h" #include "startupmanager.h" #include //#define STRUCTBUILDER_DEBUG 1 using namespace Arts; using namespace std; class StructureBuilder_impl : virtual public StructureBuilder_skel { protected: list factories; public: void addFactory(ObjectFactory factory); Object createObject(StructureDesc structure); ModuleDef createTypeInfo(StructureDesc structure); }; REGISTER_IMPLEMENTATION(StructureBuilder_impl); typedef DynamicSkeleton SynthModule_dskel; class Structure_impl : virtual public SynthModule_dskel, virtual public StdSynthModule { protected: list structureObjects; struct ForwardMethod { string method; Object destObject; string destMethod; }; list forwardMethods; public: Structure_impl(StructureDesc structure, list& factories); void streamInit(); void streamEnd(); void process(long methodID, Buffer *request, Buffer *result); }; void StructureBuilder_impl::addFactory(ObjectFactory factory) { factories.push_back(factory); } ModuleDef StructureBuilder_impl::createTypeInfo(StructureDesc structure) { ModuleDef md; InterfaceDef id; /* convert structure to InterfaceDef id */ md.moduleName = id.name = structure.name(); id.inheritedInterfaces.push_back("Arts::SynthModule"); vector *otherInterfaces = structure.inheritedInterfaces(); vector::iterator ii; for(ii = otherInterfaces->begin(); ii != otherInterfaces->end(); ii++) id.inheritedInterfaces.push_back(*ii); delete otherInterfaces; vector *ports = structure.ports(); vector::iterator pi; for(pi = ports->begin(); pi != ports->end(); pi++) { const Arts::PortType& type = pi->type(); // if we inherited the port from a tqparent interface, we don't need to // list it in our interface description if(pi->inheritedInterface().empty()) { AttributeDef ad; ad.name = pi->name(); // This is a little tricky, as input ports (which are bringing data // from outside into the structure) are saved as output ports (and // output ports as input ports). ad.flags = AttributeType( ((type.direction == input)?streamOut:streamIn) | ((type.connType == conn_stream)?attributeStream:attributeAttribute) ); ad.type = type.dataType; id.attributes.push_back(ad); } } delete ports; md.interfaces.push_back(id); return md; } namespace Arts { static class StructureBuilderCleanUp : public StartupClass { public: vector types; void startup() { }; void shutdown() { vector::iterator i; for(i = types.begin(); i != types.end(); i++) Dispatcher::the()->interfaceRepo().removeModule(*i); types.clear(); } virtual ~StructureBuilderCleanUp() {} } structureBuilderCleanUp; } Object StructureBuilder_impl::createObject(StructureDesc structure) { ModuleDef md = createTypeInfo(structure); // FIXME: find some faster way of ensuring type consistency than creating // the thing from scratch every time structureBuilderCleanUp.types.push_back(Dispatcher::the()->interfaceRepo().insertModule(md)); Object obj = Object::_from_base(new Structure_impl(structure, factories)); return obj; } Structure_impl::Structure_impl(StructureDesc structureDesc, list& factories) : SynthModule_dskel(structureDesc.name()) { map moduleMap; vector *modules = structureDesc.modules(); vector::iterator mi; // create each object for(mi = modules->begin(); mi != modules->end(); mi++) { ModuleDesc& md = *mi; #ifdef STRUCTBUILDER_DEBUG cout << "create " << md.name() << endl; #endif Object o = Object::null(); //SubClass(md.name()); Object_skel *skel = 0; skel = ObjectManager::the()->create(md.name()); if(skel) o = Object::_from_base(skel); #ifdef STRUCTBUILDER_DEBUG if(o.isNull()) cout << "no local creator for " << md.name() << endl; #endif list::iterator fi = factories.begin(); while(o.isNull() && fi != factories.end()) { o = fi->createObject(md.name()); fi++; } #ifdef STRUCTBUILDER_DEBUG if(o.isNull()) cout << "no remote creator for " << md.name() << endl; #endif assert(!o.isNull()); moduleMap[md.ID()] = o; structureObjects.push_back(o); } // connect objects and set values for(mi = modules->begin(); mi != modules->end(); mi++) { Object& object = moduleMap[mi->ID()]; vector *ports = mi->ports(); vector::iterator pi; for(pi = ports->begin(); pi != ports->end(); pi++) { PortDesc& pd = *pi; const Arts::PortType& ptype = pd.type(); if(pd.hasValue()) { // set values #ifdef STRUCTBUILDER_DEBUG cout << "value " << mi->name() << "." << pi->name() << endl; #endif if(ptype.connType == conn_property) { DynamicRequest req(object); req.method("_set_"+pi->name()); req.param(pd.value()); bool requestOk = req.invoke(); arts_assert(requestOk); } else { if(ptype.dataType == "float") setValue(object,pi->name(),pd.floatValue()); else arts_warning("unexpected property type %s", ptype.dataType.c_str()); //setStringValue(object,pd.stringValue()); } } else if(pd.isConnected() && ptype.direction == output) { // create connections vector *connections = pd.connections(); vector::iterator ci; for(ci = connections->begin(); ci != connections->end(); ci++) { if(!ci->tqparent().isNull()) // structureport otherwise { Object& dest = moduleMap[ci->tqparent().ID()]; #ifdef STRUCTBUILDER_DEBUG cout << "connect " << mi->name() << "." << pi->name() << " to " << ci->tqparent().name() << "." << ci->name() << endl; #endif connect(object,pd.name(),dest,ci->name()); } } delete connections; } } delete ports; } delete modules; // create ports (should be done via dynamic impl class...) vector *ports = structureDesc.ports(); vector::iterator pi; for(pi = ports->begin(); pi != ports->end(); pi++) { Arts::StructurePortDesc& pd = *pi; if(pd.isConnected()) { // create connections vector *connections = pd.connections(); vector::iterator ci; for(ci = connections->begin(); ci != connections->end(); ci++) { Object& dest = moduleMap[ci->tqparent().ID()]; #ifdef STRUCTBUILDER_DEBUG cout << "virtualize " << pi->name() << " to " << ci->tqparent().name() << "." << ci->name() << endl; #endif _node()->virtualize(pd.name(),dest._node(),ci->name()); if(pd.type().connType == conn_property) { ForwardMethod fm; fm.method = "_set_"+pd.name(); fm.destObject = dest; fm.destMethod = "_set_"+ci->name(); forwardMethods.push_back(fm); } } delete connections; } } delete ports; } void Structure_impl::streamInit() { list::iterator i; #ifdef STRUCTBUILDER_DEBUG cout << "vstructure: got streamInit()" << endl; #endif for(i=structureObjects.begin(); i != structureObjects.end(); i++) { if(i->_base()->_isCompatibleWith("Arts::SynthModule")) i->_node()->start(); } } void Structure_impl::streamEnd() { list::iterator i; #ifdef STRUCTBUILDER_DEBUG cout << "vstructure: got streamEnd()" << endl; #endif for(i=structureObjects.begin(); i != structureObjects.end(); i++) if(i->_base()->_isCompatibleWith("Arts::SynthModule")) i->_node()->stop(); } void Structure_impl::process(long methodID, Buffer *request, Buffer *result) { const MethodDef& methodDef = getMethodDef(methodID); arts_debug("Structure_impl: got method, method ID=%ld name='%s'", methodID, methodDef.name.c_str()); list::iterator fi; for(fi = forwardMethods.begin(); fi != forwardMethods.end(); fi++) { if(fi->method == methodDef.name) { Any a; a.type = methodDef.signature[0].type; while(request->remaining() > 0) a.value.push_back(request->readByte()); DynamicRequest(fi->destObject).method(fi->destMethod).param(a).invoke(); } } }