Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-20 08:28:01

0001 
0002 // Copyright 2023, Jefferson Science Associates, LLC.
0003 // Subject to the terms in the LICENSE file found in the top-level directory.
0004 
0005 #include <JANA/JFactory.h>
0006 #include <JANA/JEvent.h>
0007 #include <JANA/JEventSource.h>
0008 #include <JANA/Utils/JTypeInfo.h>
0009 
0010 
0011 class FlagGuard {
0012     bool* m_flag;
0013 public:
0014     FlagGuard(bool* flag) : m_flag(flag) {
0015         *m_flag = true;
0016     }
0017     ~FlagGuard() {
0018         *m_flag = false;
0019     }
0020 };
0021 
0022 void JFactory::Create(const std::shared_ptr<const JEvent>& event) {
0023     Create(*event.get());
0024 }
0025 
0026 void JFactory::Create(const JEvent& event) {
0027 
0028     if (mInsideCreate && (mStatus != Status::Inserted)) {
0029         // Ideally, we disallow any calls to Create() that end up calling it right back. However, we do allow
0030         // calls that go down to GetObjects, who inserts the data, but then RETRIEVES the same data it just inserted,
0031         // so that it can subsequently calculate and insert OTHER data. Once we refactor JEventSourceEVIOpp, we can consider
0032         // removing this weird edge case.
0033         throw JException("Encountered a cycle in the factory dependency graph! Hint: Maybe this data was supposed to be inserted in the JEventSource");
0034     }
0035     FlagGuard insideCreateFlagGuard (&mInsideCreate); // No matter how we exit from Create() (particularly with exceptions) mInsideCreate will be set back to false
0036 
0037     if (m_app == nullptr && event.GetJApplication() != nullptr) {
0038         // These are usually set by JFactoryGeneratorT, but some user code has custom JFactoryGenerators which don't!
0039         // The design of JFactoryGenerator doesn't give us a better place to inject things
0040         m_app = event.GetJApplication();
0041         m_logger = m_app->GetJParameterManager()->GetLogger(GetLoggerName());
0042     }
0043 
0044     // How do we obtain our data? The priority is as follows:
0045     // 1. JFactory::Process() if REGENERATE flag is set
0046     // 2. JEvent::Insert()
0047     // 3. JEventSource::GetObjects() if source has GetObjects() enabled
0048     // 4. JFactory::Process()
0049 
0050     // ---------------------------------------------------------------------
0051     // 1. JFactory::Process() if REGENERATE flag is set
0052     // ---------------------------------------------------------------------
0053 
0054     if (mRegenerate) {
0055         if (mStatus == Status::Inserted) {
0056             // Status::Inserted indicates that the data came from either src->GetObjects() or evt->Insert()
0057             ClearData(); 
0058             // ClearData() resets mStatus to Unprocessed so that the data will be regenerated exactly once.
0059         }
0060         // After this point, control flow falls through to "4. JFactory::Process"
0061     }
0062     else {
0063 
0064         // ---------------------------------------------------------------------
0065         // 2. JEvent::Insert()
0066         // ---------------------------------------------------------------------
0067 
0068         if (mStatus == Status::Inserted) {
0069             // This may include data cached from eventsource->GetObjects().
0070             // Either way, short-circuit here, because the data is present.
0071             return;
0072         }
0073 
0074         // ---------------------------------------------------------------------
0075         // 3. JEventSource::GetObjects() if source has GetObjects() enabled
0076         // ---------------------------------------------------------------------
0077 
0078         auto src = event.GetJEventSource();
0079         if (src != nullptr && src->IsGetObjectsEnabled()) {
0080             bool found_data = false;
0081 
0082             CallWithJExceptionWrapper("JEventSource::GetObjects", [&](){ 
0083                 found_data = src->GetObjects(event.shared_from_this(), this); });
0084 
0085             if (found_data) {
0086                 mStatus = Status::Inserted;
0087                 return;
0088             }
0089         }
0090         // If neither "2. JEvent::Insert()" nor "3. JEventSource::GetObjects()" succeeded, fall through to "4. JFactory::Process()"
0091     }
0092 
0093     // ---------------------------------------------------------------------
0094     // 4. JFactory::Process()
0095     // ---------------------------------------------------------------------
0096 
0097     // Check if init had _previously_ excepted but the cache was since cleared
0098     if (mInitStatus == InitStatus::InitExcepted && mStatus == Status::Empty) {
0099         for (auto* output : GetOutputs()) {
0100             output->LagrangianStore(*event.GetFactorySet(), JDatabundle::Status::Excepted);
0101         }
0102         for (auto* output : GetVariadicOutputs()) {
0103             output->LagrangianStore(*event.GetFactorySet(), JDatabundle::Status::Excepted);
0104         }
0105         mStatus = Status::Excepted;
0106         std::rethrow_exception(mException);
0107     }
0108 
0109     // Make sure Init() ran, which might except...
0110     try {
0111         DoInit(); // This checks mInitStatus internally before calling Init()
0112     }
0113     catch(...) {
0114         // If Init() excepts, we still need to store an empty collection
0115         mStatus = Status::Excepted;
0116         for (auto* output : GetOutputs()) {
0117             output->LagrangianStore(*event.GetFactorySet(), JDatabundle::Status::Excepted);
0118         }
0119         for (auto* output : GetVariadicOutputs()) {
0120             output->LagrangianStore(*event.GetFactorySet(), JDatabundle::Status::Excepted);
0121         }
0122         std::rethrow_exception(mException);
0123     }
0124 
0125     // At this point, Init() has run and has _not_ excepted
0126 
0127     if (mStatus == Status::Excepted) {
0128         // But Process() might have already excepted!
0129         std::rethrow_exception(mException);
0130     }
0131     else if (mStatus == Status::Empty) {
0132         // Now we know that we need to run Process() to create the data in the first place
0133         try {
0134             auto run_number = event.GetRunNumber();
0135             if (mPreviousRunNumber != run_number) {
0136                 if (m_callback_style == CallbackStyle::LegacyMode) {
0137                     if (mPreviousRunNumber != -1) {
0138                         CallWithJExceptionWrapper("JFactory::EndRun", [&](){ EndRun(); });
0139                     }
0140                     CallWithJExceptionWrapper("JFactory::ChangeRun", [&](){ ChangeRun(event.shared_from_this()); });
0141                     CallWithJExceptionWrapper("JFactory::BeginRun", [&](){ BeginRun(event.shared_from_this()); });
0142                 }
0143                 else if (m_callback_style == CallbackStyle::ExpertMode) {
0144                     CallWithJExceptionWrapper("JFactory::ChangeRun", [&](){ ChangeRun(event); });
0145                 }
0146                 mPreviousRunNumber = run_number;
0147             }
0148             for (auto* input : GetInputs()) {
0149                 input->Populate(event);
0150             }
0151             for (auto* input : GetVariadicInputs()) {
0152                 input->Populate(event);
0153             }
0154             if (m_callback_style == CallbackStyle::LegacyMode) {
0155                 CallWithJExceptionWrapper("JFactory::Process", [&](){ Process(event.shared_from_this()); });
0156             }
0157             else if (m_callback_style == CallbackStyle::ExpertMode) {
0158                 CallWithJExceptionWrapper("JFactory::Process", [&](){ Process(event); });
0159             }
0160             else {
0161                 throw JException("Invalid callback style");
0162             }
0163         }
0164         catch (...) {
0165             // Save everything already created even if we throw an exception
0166             // This is so that we leave everything in a valid state just in case someone tries to catch the exception recover,
0167             // such as EICrecon. (Remember that a missing collection in the podio frame will segfault if anyone tries to write that frame)
0168             // Note that the collections themselves won't know that they exited early
0169 
0170             LOG << "Exception in JFactory::Create, prefix=" << GetPrefix();
0171             mStatus = Status::Excepted;
0172             mException = std::current_exception();
0173             for (auto* output : GetOutputs()) {
0174                 output->LagrangianStore(*event.GetFactorySet(), JDatabundle::Status::Excepted);
0175             }
0176             for (auto* output : GetVariadicOutputs()) {
0177                 output->LagrangianStore(*event.GetFactorySet(), JDatabundle::Status::Excepted);
0178             }
0179             throw;
0180         }
0181 
0182         // Save the (successfully processed) data
0183         mStatus = Status::Processed;
0184         for (auto* output : GetOutputs()) {
0185             output->LagrangianStore(*event.GetFactorySet(), JDatabundle::Status::Created);
0186         }
0187         for (auto* output : GetVariadicOutputs()) {
0188             output->LagrangianStore(*event.GetFactorySet(), JDatabundle::Status::Created);
0189         }
0190     }
0191 }
0192 
0193 void JFactory::DoInit() {
0194     if (mInitStatus != InitStatus::InitNotRun) {
0195         return;
0196     }
0197     for (auto* parameter : m_parameters) {
0198         parameter->Init(*(m_app->GetJParameterManager()), m_prefix);
0199     }
0200     for (auto* service : m_services) {
0201         service->Fetch(m_app);
0202     }
0203     try {
0204         CallWithJExceptionWrapper("JFactory::Init", [&](){ Init(); });
0205         mInitStatus = InitStatus::InitRun;
0206     }
0207     catch (...) {
0208         mInitStatus = InitStatus::InitExcepted;
0209         mException = std::current_exception();
0210         throw;
0211     }
0212 }
0213 
0214 void JFactory::DoFinish() {
0215     if (mInitStatus == InitStatus::InitRun) {
0216         if (mPreviousRunNumber != -1) {
0217             CallWithJExceptionWrapper("JFactory::EndRun", [&](){ EndRun(); });
0218         }
0219         CallWithJExceptionWrapper("JFactory::Finish", [&](){ Finish(); });
0220     }
0221 }
0222 
0223 void JFactory::Summarize(JComponentSummary& summary) const {
0224 
0225     auto fs = new JComponentSummary::Component(
0226             "Factory",
0227             GetPrefix(),
0228             GetTypeName(),
0229             GetLevel(),
0230             GetPluginName());
0231 
0232     SummarizeInputs(*fs);
0233     SummarizeOutputs(*fs);
0234     summary.Add(fs);
0235 }
0236 
0237