00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #define FREPPLE_CORE
00029 #include "frepple/model.h"
00030 namespace frepple
00031 {
00032
00033 DECLARE_EXPORT const MetaCategory* Flow::metadata;
00034 DECLARE_EXPORT const MetaClass* FlowStart::metadata,
00035 *FlowEnd::metadata;
00036
00037
00038 int Flow::initialize()
00039 {
00040
00041 metadata = new MetaCategory
00042 ("flow", "flows", MetaCategory::ControllerDefault, writer);
00043 FlowStart::metadata = new MetaClass("flow", "flow_start",
00044 Object::createDefault<FlowStart>, true);
00045 FlowEnd::metadata = new MetaClass("flow", "flow_end",
00046 Object::createDefault<FlowEnd>);
00047
00048
00049 PythonType& x = FreppleCategory<Flow>::getType();
00050 x.setName("flow");
00051 x.setDoc("frePPLe flow");
00052 x.supportgetattro();
00053 x.supportsetattro();
00054 x.supportcreate(create);
00055 x.addMethod("toXML", toXML, METH_VARARGS, "return a XML representation");
00056 const_cast<MetaCategory*>(metadata)->pythonClass = x.type_object();
00057 return x.typeReady();
00058 }
00059
00060
00061 void Flow::writer(const MetaCategory* c, XMLOutput* o)
00062 {
00063 bool firstflow = true;
00064 for (Operation::iterator i = Operation::begin(); i != Operation::end(); ++i)
00065 for (Operation::flowlist::const_iterator j = i->getFlows().begin(); j != i->getFlows().end(); ++j)
00066 {
00067 if (firstflow)
00068 {
00069 o->BeginObject(Tags::tag_flows);
00070 firstflow = false;
00071 }
00072
00073
00074 o->writeElement(Tags::tag_flow, &*j, FULL);
00075 }
00076 if (!firstflow) o->EndObject(Tags::tag_flows);
00077 }
00078
00079
00080 DECLARE_EXPORT void Flow::validate(Action action)
00081 {
00082
00083 Operation* oper = getOperation();
00084 Buffer* buf = getBuffer();
00085 if (!oper || !buf)
00086 {
00087
00088 delete this;
00089 if (!oper && !buf)
00090 throw DataException("Missing operation and buffer on a flow");
00091 else if (!oper)
00092 throw DataException("Missing operation on a flow with buffer '"
00093 + buf->getName() + "'");
00094 else
00095 throw DataException("Missing buffer on a flow with operation '"
00096 + oper->getName() + "'");
00097 }
00098
00099
00100
00101 Operation::flowlist::const_iterator i = oper->getFlows().begin();
00102 for (; i != oper->getFlows().end(); ++i)
00103 if (i->getBuffer() == buf
00104 && i->getEffective().overlap(getEffective())
00105 && &*i != this)
00106 break;
00107
00108
00109 switch (action)
00110 {
00111 case ADD:
00112 if (i != oper->getFlows().end())
00113 {
00114 delete this;
00115 throw DataException("Flow of '" + oper->getName() + "' and '" +
00116 buf->getName() + "' already exists");
00117 }
00118 break;
00119 case CHANGE:
00120 delete this;
00121 throw DataException("Can't update a flow");
00122 case ADD_CHANGE:
00123
00124 if (i == oper->getFlows().end()) break;
00125 delete this;
00126 throw DataException("Can't update a flow");
00127 case REMOVE:
00128
00129 delete this;
00130
00131 if (i == oper->getFlows().end())
00132 throw DataException("Can't remove nonexistent flow of '"
00133 + oper->getName() + "' and '" + buf->getName() + "'");
00134
00135 delete &*i;
00136 }
00137
00138
00139
00140 if (buf->hasOwner() && action!=REMOVE) new Flow(oper, buf->getOwner(), quantity);
00141
00142
00143 HasLevel::triggerLazyRecomputation();
00144 }
00145
00146
00147 DECLARE_EXPORT Flow::~Flow()
00148 {
00149
00150 HasLevel::triggerLazyRecomputation();
00151
00152
00153 if (getOperation() && getBuffer())
00154 {
00155
00156 for(OperationPlan::iterator i(getOperation()); i != OperationPlan::end(); ++i)
00157
00158 for(OperationPlan::FlowPlanIterator j = i->beginFlowPlans(); j != i->endFlowPlans(); )
00159 if (j->getFlow() == this) j.deleteFlowPlan();
00160 else ++j;
00161 }
00162
00163
00164 if (getOperation()) getOperation()->flowdata.erase(this);
00165 if (getBuffer()) getBuffer()->flows.erase(this);
00166
00167
00168 if (hasAlts)
00169 {
00170
00171
00172
00173 unsigned short cnt = 0;
00174 int minprio = INT_MAX;
00175 Flow* newLeader = NULL;
00176 for (Operation::flowlist::iterator i = getOperation()->flowdata.begin();
00177 i != getOperation()->flowdata.end(); ++i)
00178 if (i->altFlow == this)
00179 {
00180 cnt++;
00181 if (i->priority < minprio)
00182 {
00183 newLeader = &*i;
00184 minprio = i->priority;
00185 }
00186 }
00187 if (cnt < 1)
00188 throw LogicException("Alternate flows update failure");
00189 else if (cnt == 1)
00190
00191 newLeader->altFlow = NULL;
00192 else
00193 {
00194
00195 newLeader->hasAlts = true;
00196 newLeader->altFlow = NULL;
00197 for (Operation::flowlist::iterator i = getOperation()->flowdata.begin();
00198 i != getOperation()->flowdata.end(); ++i)
00199 if (i->altFlow == this) i->altFlow = newLeader;
00200 }
00201 }
00202 if (altFlow)
00203 {
00204
00205
00206
00207 bool only_one = true;
00208 for (Operation::flowlist::iterator i = getOperation()->flowdata.begin();
00209 i != getOperation()->flowdata.end(); ++i)
00210 if (i->altFlow == altFlow)
00211 {
00212 only_one = false;
00213 break;
00214 }
00215 if (only_one) altFlow->hasAlts = false;
00216 }
00217 }
00218
00219
00220 DECLARE_EXPORT void Flow::setAlternate(Flow *f)
00221 {
00222
00223 if (!f)
00224 throw DataException("Setting NULL alternate flow");
00225 if (hasAlts || f->altFlow)
00226 throw DataException("Nested alternate flows are not allowed");
00227 if (!f->isConsumer() || !isConsumer())
00228 throw DataException("Only consuming alternate flows are supported");
00229
00230
00231 f->hasAlts = true;
00232 altFlow = f;
00233 }
00234
00235
00236 DECLARE_EXPORT void Flow::setAlternate(const string& n)
00237 {
00238 if (!getOperation())
00239 throw LogicException("Can't set an alternate flow before setting the operation");
00240 Flow *x = getOperation()->flowdata.find(n);
00241 if (!x) throw DataException("Can't find flow with name '" + n + "'");
00242 setAlternate(x);
00243 }
00244
00245
00246 DECLARE_EXPORT void Flow::writeElement (XMLOutput *o, const Keyword& tag, mode m) const
00247 {
00248
00249
00250 if (m == REFERENCE) return;
00251 assert(m != NOHEADER);
00252
00253
00254 o->BeginObject(tag, Tags::tag_type, getType().type);
00255
00256
00257
00258 if (!dynamic_cast<Operation*>(o->getPreviousObject()))
00259 o->writeElement(Tags::tag_operation, getOperation());
00260
00261
00262
00263 if (!dynamic_cast<Buffer*>(o->getPreviousObject()))
00264 o->writeElement(Tags::tag_buffer, getBuffer());
00265
00266
00267 o->writeElement(Tags::tag_quantity, getQuantity());
00268 if (getPriority()!=1) o->writeElement(Tags::tag_priority, getPriority());
00269 if (!getName().empty()) o->writeElement(Tags::tag_name, getName());
00270 if (getAlternate())
00271 o->writeElement(Tags::tag_alternate, getAlternate()->getName());
00272
00273
00274 if (getEffective().getStart() != Date::infinitePast)
00275 o->writeElement(Tags::tag_effective_start, getEffective().getStart());
00276 if (getEffective().getEnd() != Date::infiniteFuture)
00277 o->writeElement(Tags::tag_effective_end, getEffective().getEnd());
00278
00279
00280 o->EndObject(tag);
00281 }
00282
00283
00284 DECLARE_EXPORT void Flow::beginElement(XMLInput& pIn, const Attribute& pAttr)
00285 {
00286 if (pAttr.isA (Tags::tag_buffer))
00287 pIn.readto( Buffer::reader(Buffer::metadata,pIn.getAttributes()) );
00288 else if (pAttr.isA (Tags::tag_operation))
00289 pIn.readto( Operation::reader(Operation::metadata,pIn.getAttributes()) );
00290 }
00291
00292
00293 DECLARE_EXPORT void Flow::endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00294 {
00295 if (pAttr.isA (Tags::tag_buffer))
00296 {
00297 Buffer * b = dynamic_cast<Buffer*>(pIn.getPreviousObject());
00298 if (b) setBuffer(b);
00299 else throw LogicException("Incorrect object type during read operation");
00300 }
00301 else if (pAttr.isA (Tags::tag_operation))
00302 {
00303 Operation * o = dynamic_cast<Operation*>(pIn.getPreviousObject());
00304 if (o) setOperation(o);
00305 else throw LogicException("Incorrect object type during read operation");
00306 }
00307 else if (pAttr.isA(Tags::tag_quantity))
00308 setQuantity(pElement.getDouble());
00309 else if (pAttr.isA(Tags::tag_priority))
00310 setPriority(pElement.getInt());
00311 else if (pAttr.isA(Tags::tag_name))
00312 setName(pElement.getString());
00313 else if (pAttr.isA(Tags::tag_alternate))
00314 setAlternate(pElement.getString());
00315 else if (pAttr.isA(Tags::tag_search))
00316 setSearch(pElement.getString());
00317 else if (pAttr.isA(Tags::tag_action))
00318 {
00319 delete static_cast<Action*>(pIn.getUserArea());
00320 pIn.setUserArea(
00321 new Action(MetaClass::decodeAction(pElement.getString().c_str()))
00322 );
00323 }
00324 else if (pAttr.isA(Tags::tag_effective_end))
00325 setEffectiveEnd(pElement.getDate());
00326 else if (pAttr.isA(Tags::tag_effective_start))
00327 setEffectiveStart(pElement.getDate());
00328 else if (pIn.isObjectEnd())
00329 {
00330
00331 Action a = pIn.getUserArea() ?
00332 *static_cast<Action*>(pIn.getUserArea()) :
00333 ADD_CHANGE;
00334 delete static_cast<Action*>(pIn.getUserArea());
00335 validate(a);
00336 }
00337 }
00338
00339
00340 DECLARE_EXPORT void FlowEnd::writeElement
00341 (XMLOutput *o, const Keyword& tag, mode m) const
00342 {
00343
00344
00345 if (m == REFERENCE) return;
00346 assert(m != NOHEADER);
00347
00348
00349 o->BeginObject(tag, Tags::tag_type, getType().type);
00350
00351
00352
00353 if (!dynamic_cast<Operation*>(o->getPreviousObject()))
00354 o->writeElement(Tags::tag_operation, getOperation());
00355
00356
00357
00358 if (!dynamic_cast<Buffer*>(o->getPreviousObject()))
00359 o->writeElement(Tags::tag_buffer, getBuffer());
00360
00361
00362 o->writeElement(Tags::tag_quantity, getQuantity());
00363 if (getPriority()!=1) o->writeElement(Tags::tag_priority, getPriority());
00364 if (!getName().empty()) o->writeElement(Tags::tag_name, getName());
00365 if (getAlternate())
00366 o->writeElement(Tags::tag_alternate, getAlternate()->getName());
00367
00368
00369 if (getEffective().getStart() != Date::infinitePast)
00370 o->writeElement(Tags::tag_effective_start, getEffective().getStart());
00371 if (getEffective().getEnd() != Date::infiniteFuture)
00372 o->writeElement(Tags::tag_effective_end, getEffective().getEnd());
00373
00374
00375 o->EndObject(tag);
00376 }
00377
00378
00379 DECLARE_EXPORT PyObject* Flow::getattro(const Attribute& attr)
00380 {
00381 if (attr.isA(Tags::tag_buffer))
00382 return PythonObject(getBuffer());
00383 if (attr.isA(Tags::tag_operation))
00384 return PythonObject(getOperation());
00385 if (attr.isA(Tags::tag_quantity))
00386 return PythonObject(getQuantity());
00387 if (attr.isA(Tags::tag_priority))
00388 return PythonObject(getPriority());
00389 if (attr.isA(Tags::tag_effective_end))
00390 return PythonObject(getEffective().getEnd());
00391 if (attr.isA(Tags::tag_effective_start))
00392 return PythonObject(getEffective().getStart());
00393 if (attr.isA(Tags::tag_name))
00394 return PythonObject(getName());
00395 if (attr.isA(Tags::tag_alternate))
00396 return PythonObject(getAlternate());
00397 if (attr.isA(Tags::tag_search))
00398 {
00399 ostringstream ch;
00400 ch << getSearch();
00401 return PythonObject(ch.str());
00402 }
00403 return NULL;
00404 }
00405
00406
00407 DECLARE_EXPORT int Flow::setattro(const Attribute& attr, const PythonObject& field)
00408 {
00409 if (attr.isA(Tags::tag_buffer))
00410 {
00411 if (!field.check(Buffer::metadata))
00412 {
00413 PyErr_SetString(PythonDataException, "flow buffer must be of type buffer");
00414 return -1;
00415 }
00416 Buffer* y = static_cast<Buffer*>(static_cast<PyObject*>(field));
00417 setBuffer(y);
00418 }
00419 else if (attr.isA(Tags::tag_operation))
00420 {
00421 if (!field.check(Operation::metadata))
00422 {
00423 PyErr_SetString(PythonDataException, "flow operation must be of type operation");
00424 return -1;
00425 }
00426 Operation* y = static_cast<Operation*>(static_cast<PyObject*>(field));
00427 setOperation(y);
00428 }
00429 else if (attr.isA(Tags::tag_quantity))
00430 setQuantity(field.getDouble());
00431 else if (attr.isA(Tags::tag_priority))
00432 setPriority(field.getInt());
00433 else if (attr.isA(Tags::tag_effective_end))
00434 setEffectiveEnd(field.getDate());
00435 else if (attr.isA(Tags::tag_effective_start))
00436 setEffectiveStart(field.getDate());
00437 else if (attr.isA(Tags::tag_name))
00438 setName(field.getString());
00439 else if (attr.isA(Tags::tag_alternate))
00440 {
00441 if (!field.check(Flow::metadata))
00442 setAlternate(field.getString());
00443 else
00444 {
00445 Flow *y = static_cast<Flow*>(static_cast<PyObject*>(field));
00446 setAlternate(y);
00447 }
00448 }
00449 else if (attr.isA(Tags::tag_search))
00450 setSearch(field.getString());
00451 else
00452 return -1;
00453 return 0;
00454 }
00455
00456
00457
00458 PyObject* Flow::create(PyTypeObject* pytype, PyObject* args, PyObject* kwds)
00459 {
00460 try
00461 {
00462
00463 PyObject* oper = PyDict_GetItemString(kwds,"operation");
00464 if (!PyObject_TypeCheck(oper, Operation::metadata->pythonClass))
00465 throw DataException("flow operation must be of type operation");
00466
00467
00468 PyObject* buf = PyDict_GetItemString(kwds,"buffer");
00469 if (!PyObject_TypeCheck(buf, Buffer::metadata->pythonClass))
00470 throw DataException("flow buffer must be of type buffer");
00471
00472
00473 PyObject* q1 = PyDict_GetItemString(kwds,"quantity");
00474 double q2 = q1 ? PythonObject(q1).getDouble() : 1.0;
00475
00476
00477 Flow *l;
00478 PyObject* t = PyDict_GetItemString(kwds,"type");
00479 if (t)
00480 {
00481 PythonObject d(t);
00482 if (d.getString() == "flow_end")
00483 l = new FlowEnd(
00484 static_cast<Operation*>(oper),
00485 static_cast<Buffer*>(buf),
00486 q2
00487 );
00488 else
00489 l = new FlowStart(
00490 static_cast<Operation*>(oper),
00491 static_cast<Buffer*>(buf),
00492 q2
00493 );
00494 }
00495 else
00496 l = new FlowStart(
00497 static_cast<Operation*>(oper),
00498 static_cast<Buffer*>(buf),
00499 q2
00500 );
00501
00502
00503 PyObject* eff_start = PyDict_GetItemString(kwds,"effective_start");
00504 if (eff_start)
00505 {
00506 PythonObject d(eff_start);
00507 l->setEffectiveStart(d.getDate());
00508 }
00509
00510
00511 PyObject* eff_end = PyDict_GetItemString(kwds,"effective_end");
00512 if (eff_end)
00513 {
00514 PythonObject d(eff_end);
00515 l->setEffectiveEnd(d.getDate());
00516 }
00517
00518
00519 Py_INCREF(l);
00520 return static_cast<PyObject*>(l);
00521 }
00522 catch (...)
00523 {
00524 PythonType::evalException();
00525 return NULL;
00526 }
00527 }
00528
00529
00530 int FlowIterator::initialize()
00531 {
00532
00533 PythonType& x = PythonExtension<FlowIterator>::getType();
00534 x.setName("flowIterator");
00535 x.setDoc("frePPLe iterator for flows");
00536 x.supportiter();
00537 return x.typeReady();
00538 }
00539
00540
00541 PyObject* FlowIterator::iternext()
00542 {
00543 PyObject* result;
00544 if (buf)
00545 {
00546
00547 if (ib == buf->getFlows().end()) return NULL;
00548 result = const_cast<Flow*>(&*ib);
00549 ++ib;
00550 }
00551 else
00552 {
00553
00554 if (io == oper->getFlows().end()) return NULL;
00555 result = const_cast<Flow*>(&*io);
00556 ++io;
00557 }
00558 Py_INCREF(result);
00559 return result;
00560 }
00561
00562 }