From 7aba1410fbedc985069b80c1e58126cefa3376ed Mon Sep 17 00:00:00 2001 From: Nathan Brei Date: Thu, 2 May 2024 15:15:19 -0400 Subject: [PATCH 1/9] Add JComponent::CallWithJExceptionWrapper This will substantially clean up our component internals, while making exception handling more consistent and reliable --- src/libraries/JANA/Omni/JComponent.h | 26 +++++++++++++++++++++++++ src/libraries/JANA/Omni/JComponentFwd.h | 2 ++ 2 files changed, 28 insertions(+) diff --git a/src/libraries/JANA/Omni/JComponent.h b/src/libraries/JANA/Omni/JComponent.h index b37ab587e..ea51f60b2 100644 --- a/src/libraries/JANA/Omni/JComponent.h +++ b/src/libraries/JANA/Omni/JComponent.h @@ -112,6 +112,32 @@ class JComponent::Service : public JComponent::ServiceBase { }; +template +inline void JComponent::CallWithJExceptionWrapper(std::string func_name, F func) { + try { + func(); + } + catch (JException& ex) { + if (ex.plugin_name.empty()) ex.plugin_name = m_plugin_name; + if (ex.component_name.empty()) ex.component_name = m_type_name; + throw ex; + } + catch (std::exception& e) { + auto ex = JException("Exception in %s: %s", func_name.c_str(), e.what()); + ex.nested_exception = std::current_exception(); + ex.plugin_name = m_plugin_name; + ex.component_name = m_type_name; + throw ex; + } + catch (...) { + auto ex = JException("Unknown exception in %s", func_name.c_str()); + ex.nested_exception = std::current_exception(); + ex.plugin_name = m_plugin_name; + ex.component_name = m_type_name; + throw ex; + } +} + } // namespace omni } // namespace jana diff --git a/src/libraries/JANA/Omni/JComponentFwd.h b/src/libraries/JANA/Omni/JComponentFwd.h index 321b8551c..d23562721 100644 --- a/src/libraries/JANA/Omni/JComponentFwd.h +++ b/src/libraries/JANA/Omni/JComponentFwd.h @@ -89,6 +89,8 @@ struct JComponent { void SetLogger(JLogger logger) { m_logger = logger; } + template + inline void CallWithJExceptionWrapper(std::string func_name, F func); // --------------------- // "Registered member" helpers From 6b8791a819c0739705fee5234606653dfee660f7 Mon Sep 17 00:00:00 2001 From: Nathan Brei Date: Thu, 2 May 2024 16:11:21 -0400 Subject: [PATCH 2/9] Factor out exception handling from components --- src/libraries/JANA/JEventProcessor.h | 125 ++++--------- src/libraries/JANA/JEventSource.h | 261 ++++++++++----------------- src/libraries/JANA/JEventUnfolder.h | 212 ++++++++-------------- src/libraries/JANA/JMultifactory.cc | 64 +++---- 4 files changed, 231 insertions(+), 431 deletions(-) diff --git a/src/libraries/JANA/JEventProcessor.h b/src/libraries/JANA/JEventProcessor.h index 7006b0d02..d82a8701e 100644 --- a/src/libraries/JANA/JEventProcessor.h +++ b/src/libraries/JANA/JEventProcessor.h @@ -35,28 +35,14 @@ class JEventProcessor : public jana::omni::JComponent, virtual void DoInitialize() { - try { - for (auto* parameter : m_parameters) { - parameter->Configure(*(m_app->GetJParameterManager()), m_prefix); - } - for (auto* service : m_services) { - service->Init(m_app); - } - Init(); - m_status = Status::Initialized; + for (auto* parameter : m_parameters) { + parameter->Configure(*(m_app->GetJParameterManager()), m_prefix); } - catch (JException& ex) { - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; - } - catch (...) { - auto ex = JException("Unknown exception in JEventProcessor::Open()"); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; + for (auto* service : m_services) { + service->Init(m_app); } + CallWithJExceptionWrapper("JEventProcessor::Init", [&](){ Init(); }); + m_status = Status::Initialized; } @@ -78,84 +64,51 @@ class JEventProcessor : public jana::omni::JComponent, virtual void DoReduce(const std::shared_ptr& e) { - try { - auto run_number = e->GetRunNumber(); - std::lock_guard lock(m_mutex); + auto run_number = e->GetRunNumber(); + std::lock_guard lock(m_mutex); - if (m_status == Status::Uninitialized) { - DoInitialize(); - } - else if (m_status == Status::Finalized) { - throw JException("JEventProcessor: Attempted to call DoMap() after Finalize()"); - } - if (m_last_run_number != run_number) { - if (m_last_run_number != -1) { - EndRun(); - } - for (auto* resource : m_resources) { - resource->ChangeRun(e->GetRunNumber(), m_app); - } - m_last_run_number = run_number; - BeginRun(e); - } - for (auto* input : m_inputs) { - input->GetCollection(*e); - } - if (m_callback_style == CallbackStyle::DeclarativeMode) { - Process(e->GetRunNumber(), e->GetEventNumber(), e->GetEventIndex()); - } - else if (m_callback_style == CallbackStyle::ExpertMode) { - Process(*e); + if (m_status == Status::Uninitialized) { + DoInitialize(); + } + else if (m_status == Status::Finalized) { + throw JException("JEventProcessor: Attempted to call DoMap() after Finalize()"); + } + if (m_last_run_number != run_number) { + if (m_last_run_number != -1) { + CallWithJExceptionWrapper("JEventProcessor::EndRun", [&](){ EndRun(); }); } - else { - Process(e); + for (auto* resource : m_resources) { + resource->ChangeRun(e->GetRunNumber(), m_app); } - m_event_count += 1; + m_last_run_number = run_number; + CallWithJExceptionWrapper("JEventProcessor::BeginRun", [&](){ BeginRun(e); }); + } + for (auto* input : m_inputs) { + input->GetCollection(*e); } - catch (JException& ex) { - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; + if (m_callback_style == CallbackStyle::DeclarativeMode) { + CallWithJExceptionWrapper("JEventProcessor::Process", [&](){ + Process(e->GetRunNumber(), e->GetEventNumber(), e->GetEventIndex()); + }); } - catch (std::exception& e) { - auto ex = JException(e.what()); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; + else if (m_callback_style == CallbackStyle::ExpertMode) { + CallWithJExceptionWrapper("JEventProcessor::Process", [&](){ Process(*e); }); } - catch (...) { - auto ex = JException("Unknown exception in JEventProcessor::DoReduce()"); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; + else { + CallWithJExceptionWrapper("JEventProcessor::Process", [&](){ Process(e); }); } + m_event_count += 1; } virtual void DoFinalize() { - try { - std::lock_guard lock(m_mutex); - if (m_status != Status::Finalized) { - if (m_last_run_number != -1) { - EndRun(); - } - Finish(); - m_status = Status::Finalized; + std::lock_guard lock(m_mutex); + if (m_status != Status::Finalized) { + if (m_last_run_number != -1) { + CallWithJExceptionWrapper("JEventProcessor::EndRun", [&](){ EndRun(); }); } - } - catch (JException& ex) { - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; - } - catch (...) { - auto ex = JException("Unknown exception in JEventProcessor::Finish()"); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; + CallWithJExceptionWrapper("JEventProcessor::Finish", [&](){ Finish(); }); + m_status = Status::Finalized; } } diff --git a/src/libraries/JANA/JEventSource.h b/src/libraries/JANA/JEventSource.h index 3b63a03d5..424c50dcc 100644 --- a/src/libraries/JANA/JEventSource.h +++ b/src/libraries/JANA/JEventSource.h @@ -117,96 +117,54 @@ class JEventSource : public jana::omni::JComponent, public jana::omni::JHasOutpu // Wrappers for calling Open and GetEvent in a safe way virtual void DoInitialize(bool with_lock=true) { - try { - if (with_lock) { - std::lock_guard lock(m_mutex); - if (m_status == Status::Uninitialized) { - Open(); - if (GetResourceName().empty()) { - LOG_INFO(GetLogger()) << "Opened event source" << LOG_END; - } - else { - LOG_INFO(GetLogger()) << "Opened event source '" << GetResourceName() << "'" << LOG_END; - } - m_status = Status::Initialized; - } - } - else { - if (m_status == Status::Uninitialized) { - Open(); - if (GetResourceName().empty()) { - LOG_INFO(GetLogger()) << "Opened event source" << LOG_END; - } - else { - LOG_INFO(GetLogger()) << "Opened event source '" << GetResourceName() << "'" << LOG_END; - } - m_status = Status::Initialized; - } - } - } - catch (JException& ex) { - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; - } - catch (std::exception& e){ - auto ex = JException("Exception in JEventSource::Open(): %s", e.what()); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; - } - catch (...) { - auto ex = JException("Unknown exception in JEventSource::Open()"); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; - } - } - - virtual void DoFinalize(bool with_lock=true) { - try { - if (with_lock) { - std::lock_guard lock(m_mutex); - Close(); + if (with_lock) { + std::lock_guard lock(m_mutex); + if (m_status == Status::Uninitialized) { + CallWithJExceptionWrapper("JEventSource::Open", [&](){ Open();}); if (GetResourceName().empty()) { - LOG_INFO(GetLogger()) << "Closed event source" << LOG_END; + LOG_INFO(GetLogger()) << "Opened event source" << LOG_END; } else { - LOG_INFO(GetLogger()) << "Closed event source '" << GetResourceName() << "'" << LOG_END; + LOG_INFO(GetLogger()) << "Opened event source '" << GetResourceName() << "'" << LOG_END; } - m_status = Status::Finalized; + m_status = Status::Initialized; } - else { - Close(); + } + else { + if (m_status == Status::Uninitialized) { + CallWithJExceptionWrapper("JEventSource::Open", [&](){ Open();}); if (GetResourceName().empty()) { - LOG_INFO(GetLogger()) << "Closed event source" << LOG_END; + LOG_INFO(GetLogger()) << "Opened event source" << LOG_END; } else { - LOG_INFO(GetLogger()) << "Closed event source '" << GetResourceName() << "'" << LOG_END; + LOG_INFO(GetLogger()) << "Opened event source '" << GetResourceName() << "'" << LOG_END; } - m_status = Status::Finalized; + m_status = Status::Initialized; } } - catch (JException& ex) { - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; - } - catch (std::exception& e){ - auto ex = JException("Exception in JEventSource::Close(): %s", e.what()); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; + } + + virtual void DoFinalize(bool with_lock=true) { + if (with_lock) { + std::lock_guard lock(m_mutex); + CallWithJExceptionWrapper("JEventSource::Close", [&](){ Close();}); + if (GetResourceName().empty()) { + LOG_INFO(GetLogger()) << "Closed event source" << LOG_END; + } + else { + LOG_INFO(GetLogger()) << "Closed event source '" << GetResourceName() << "'" << LOG_END; + } + m_status = Status::Finalized; } - catch (...) { - auto ex = JException("Unknown exception in JEventSource::Close()"); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; + else { + CallWithJExceptionWrapper("JEventSource::Close", [&](){ Close();}); + if (GetResourceName().empty()) { + LOG_INFO(GetLogger()) << "Closed event source" << LOG_END; + } + else { + LOG_INFO(GetLogger()) << "Closed event source '" << GetResourceName() << "'" << LOG_END; + } + m_status = Status::Finalized; } } @@ -221,81 +179,63 @@ class JEventSource : public jana::omni::JComponent, public jana::omni::JHasOutpu auto first_evt_nr = m_nskip; auto last_evt_nr = m_nevents + m_nskip; - try { - if (m_status == Status::Uninitialized) { - DoInitialize(false); + if (m_status == Status::Uninitialized) { + DoInitialize(false); + } + if (m_status == Status::Initialized) { + if (m_nevents != 0 && (m_event_count == last_evt_nr)) { + // We exit early (and recycle) because we hit our jana:nevents limit + DoFinalize(false); + return Result::FailureFinished; } - if (m_status == Status::Initialized) { - if (m_nevents != 0 && (m_event_count == last_evt_nr)) { - // We exit early (and recycle) because we hit our jana:nevents limit - DoFinalize(false); - return Result::FailureFinished; - } - // If we reach this point, we will need to actually read an event - - // We configure the event - event->SetEventNumber(m_event_count); // Default event number to event count - event->SetJApplication(m_app); - event->SetJEventSource(this); - event->SetSequential(false); - event->GetJCallGraphRecorder()->Reset(); - - // Now we call the new-style interface - auto previous_origin = event->GetJCallGraphRecorder()->SetInsertDataOrigin( JCallGraphRecorder::ORIGIN_FROM_SOURCE); // (see note at top of JCallGraphRecorder.h) - auto result = Emit(*event); - event->GetJCallGraphRecorder()->SetInsertDataOrigin( previous_origin ); - - if (result == Result::Success) { - m_event_count += 1; - // We end up here if we read an entry in our file or retrieved a message from our socket, - // and believe we could obtain another one immediately if we wanted to - for (auto* output : m_outputs) { - output->InsertCollection(*event); - } - if (m_event_count <= first_evt_nr) { - // We immediately throw away this whole event because of nskip - // (although really we should be handling this with Seek()) - return Result::FailureTryAgain; - } - return Result::Success; + // If we reach this point, we will need to actually read an event + + // We configure the event + event->SetEventNumber(m_event_count); // Default event number to event count + event->SetJApplication(m_app); + event->SetJEventSource(this); + event->SetSequential(false); + event->GetJCallGraphRecorder()->Reset(); + + // Now we call the new-style interface + auto previous_origin = event->GetJCallGraphRecorder()->SetInsertDataOrigin( JCallGraphRecorder::ORIGIN_FROM_SOURCE); // (see note at top of JCallGraphRecorder.h) + JEventSource::Result result; + CallWithJExceptionWrapper("JEventSource::Emit", [&](){ + result = Emit(*event); + }); + event->GetJCallGraphRecorder()->SetInsertDataOrigin( previous_origin ); + + if (result == Result::Success) { + m_event_count += 1; + // We end up here if we read an entry in our file or retrieved a message from our socket, + // and believe we could obtain another one immediately if we wanted to + for (auto* output : m_outputs) { + output->InsertCollection(*event); } - else if (result == Result::FailureFinished) { - // We end up here if we tried to read an entry in a file, but found EOF - // or if we received a message from a socket that contained no data and indicated no more data will be coming - DoFinalize(false); - return Result::FailureFinished; - } - else if (result == Result::FailureTryAgain) { - // We end up here if we tried to read an entry in a file but it is on a tape drive and isn't ready yet - // or if we polled the socket, found no new messages, but still expect messages later + if (m_event_count <= first_evt_nr) { + // We immediately throw away this whole event because of nskip + // (although really we should be handling this with Seek()) return Result::FailureTryAgain; } - else { - throw JException("Invalid JEventSource::Result value!"); - } + return Result::Success; } - else { // status == Finalized + else if (result == Result::FailureFinished) { + // We end up here if we tried to read an entry in a file, but found EOF + // or if we received a message from a socket that contained no data and indicated no more data will be coming + DoFinalize(false); return Result::FailureFinished; } + else if (result == Result::FailureTryAgain) { + // We end up here if we tried to read an entry in a file but it is on a tape drive and isn't ready yet + // or if we polled the socket, found no new messages, but still expect messages later + return Result::FailureTryAgain; + } + else { + throw JException("Invalid JEventSource::Result value!"); + } } - catch (JException& ex) { - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; - } - catch (std::exception& e){ - auto ex = JException("Exception in JEventSource::Emit(): %s", e.what()); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; - } - catch (...) { - auto ex = JException("Unknown exception in JEventSource::Emit()"); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; + else { // status == Finalized + return Result::FailureFinished; } } @@ -313,7 +253,9 @@ class JEventSource : public jana::omni::JComponent, public jana::omni::JHasOutpu // Skip these events due to nskip event->SetEventNumber(m_event_count); // Default event number to event count auto previous_origin = event->GetJCallGraphRecorder()->SetInsertDataOrigin( JCallGraphRecorder::ORIGIN_FROM_SOURCE); // (see note at top of JCallGraphRecorder.h) - GetEvent(event); + CallWithJExceptionWrapper("JEventSource::GetEvent", [&](){ + GetEvent(event); + }); event->GetJCallGraphRecorder()->SetInsertDataOrigin( previous_origin ); m_event_count += 1; return Result::FailureTryAgain; // Reject this event and recycle it @@ -330,7 +272,9 @@ class JEventSource : public jana::omni::JComponent, public jana::omni::JHasOutpu event->SetSequential(false); event->GetJCallGraphRecorder()->Reset(); auto previous_origin = event->GetJCallGraphRecorder()->SetInsertDataOrigin( JCallGraphRecorder::ORIGIN_FROM_SOURCE); // (see note at top of JCallGraphRecorder.h) - GetEvent(event); + CallWithJExceptionWrapper("JEventSource::GetEvent", [&](){ + GetEvent(event); + }); for (auto* output : m_outputs) { output->InsertCollection(*event); } @@ -363,25 +307,6 @@ class JEventSource : public jana::omni::JComponent, public jana::omni::JHasOutpu return Result::Success; } } - catch (JException& ex) { - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; - } - catch (std::exception& e){ - auto ex = JException("Exception in JEventSource::GetEvent(): %s", e.what()); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; - } - catch (...) { - auto ex = JException("Unknown exception in JEventSource::GetEvent()"); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; - } } /// Calls the optional-and-discouraged user-provided FinishEvent virtual method, enforcing @@ -391,7 +316,9 @@ class JEventSource : public jana::omni::JComponent, public jana::omni::JHasOutpu void DoFinish(JEvent& event) { if (m_enable_free_event) { std::lock_guard lock(m_mutex); - FinishEvent(event); + CallWithJExceptionWrapper("JEventSource::FinishEvent", [&](){ + FinishEvent(event); + }); } } diff --git a/src/libraries/JANA/JEventUnfolder.h b/src/libraries/JANA/JEventUnfolder.h index 73882b1d6..289aee307 100644 --- a/src/libraries/JANA/JEventUnfolder.h +++ b/src/libraries/JANA/JEventUnfolder.h @@ -60,170 +60,112 @@ class JEventUnfolder : public jana::omni::JComponent, // Backend void DoInit() { - try { - std::lock_guard lock(m_mutex); - // TODO: Obtain overrides of collection names from param manager - - for (auto* parameter : m_parameters) { - parameter->Configure(*(m_app->GetJParameterManager()), m_prefix); - } - for (auto* service : m_services) { - service->Init(m_app); - } - if (m_status == Status::Uninitialized) { - Init(); - m_status = Status::Initialized; - } - else { - throw JException("JEventUnfolder: Attempting to initialize twice or from an invalid state"); - } + std::lock_guard lock(m_mutex); + // TODO: Obtain overrides of collection names from param manager + + for (auto* parameter : m_parameters) { + parameter->Configure(*(m_app->GetJParameterManager()), m_prefix); + } + for (auto* service : m_services) { + service->Init(m_app); } - catch (JException& ex) { - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; + if (m_status == Status::Uninitialized) { + CallWithJExceptionWrapper("JEventUnfolder::Init", [&](){ + Init(); + }); + m_status = Status::Initialized; } - catch (...) { - auto ex = JException("JEventUnfolder: Exception in Init()"); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; + else { + throw JException("JEventUnfolder: Attempting to initialize twice or from an invalid state"); } } void DoPreprocess(const JEvent& parent) { - try { - { - std::lock_guard lock(m_mutex); - if (m_status != Status::Initialized) { - throw JException("JEventUnfolder: Component needs to be initialized and not finalized before Unfold can be called"); - // TODO: Consider calling Initialize(with_lock=false) like we do elsewhere - } - } - for (auto* input : m_inputs) { - input->PrefetchCollection(parent); - } - if (m_callback_style != CallbackStyle::DeclarativeMode) { - Preprocess(parent); - } - } - catch (JException& ex) { - ex.plugin_name = m_plugin_name; - if (ex.component_name.empty()) { - ex.component_name = m_type_name; + { + std::lock_guard lock(m_mutex); + if (m_status != Status::Initialized) { + throw JException("JEventUnfolder: Component needs to be initialized and not finalized before Unfold can be called"); + // TODO: Consider calling Initialize(with_lock=false) like we do elsewhere } - throw ex; } - catch (std::exception& e) { - auto ex = JException("Exception in JEventUnfolder::DoPreprocess(): %s", e.what()); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; + for (auto* input : m_inputs) { + input->PrefetchCollection(parent); } - catch (...) { - auto ex = JException("Unknown exception in JEventUnfolder::DoPreprocess()"); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; + if (m_callback_style != CallbackStyle::DeclarativeMode) { + CallWithJExceptionWrapper("JEventUnfolder::Preprocess", [&](){ + Preprocess(parent); + }); } } Result DoUnfold(const JEvent& parent, JEvent& child) { - try { - std::lock_guard lock(m_mutex); - if (m_status == Status::Initialized) { - if (!m_call_preprocess_upstream) { - if (!m_enable_simplified_callbacks) { + std::lock_guard lock(m_mutex); + if (m_status == Status::Initialized) { + if (!m_call_preprocess_upstream) { + if (!m_enable_simplified_callbacks) { + CallWithJExceptionWrapper("JEventUnfolder::Preprocess", [&](){ Preprocess(parent); - } - } - if (m_last_run_number != parent.GetRunNumber()) { - for (auto* resource : m_resources) { - resource->ChangeRun(parent.GetRunNumber(), m_app); - } - if (m_callback_style == CallbackStyle::DeclarativeMode) { - ChangeRun(parent.GetRunNumber()); - } - else { - ChangeRun(parent); - } - m_last_run_number = parent.GetRunNumber(); + }); } - for (auto* input : m_inputs) { - input->GetCollection(parent); - // TODO: This requires that all inputs come from the parent. - // However, eventually we will want to support inputs - // that come from the child. - } - for (auto* output : m_outputs) { - output->Reset(); + } + if (m_last_run_number != parent.GetRunNumber()) { + for (auto* resource : m_resources) { + resource->ChangeRun(parent.GetRunNumber(), m_app); } - Result result; - child.SetEventIndex(m_child_number); - if (m_enable_simplified_callbacks) { - result = Unfold(parent.GetEventNumber(), child.GetEventNumber(), m_child_number); + if (m_callback_style == CallbackStyle::DeclarativeMode) { + CallWithJExceptionWrapper("JEventUnfolder::ChangeRun", [&](){ + ChangeRun(parent.GetRunNumber()); + }); } else { - result = Unfold(parent, child, m_child_number); - } - for (auto* output : m_outputs) { - output->InsertCollection(child); - } - m_child_number += 1; - if (result == Result::NextChildNextParent || result == Result::KeepChildNextParent) { - m_child_number = 0; + CallWithJExceptionWrapper("JEventUnfolder::ChangeRun", [&](){ + ChangeRun(parent); + }); } - return result; + m_last_run_number = parent.GetRunNumber(); + } + for (auto* input : m_inputs) { + input->GetCollection(parent); + // TODO: This requires that all inputs come from the parent. + // However, eventually we will want to support inputs + // that come from the child. + } + for (auto* output : m_outputs) { + output->Reset(); + } + Result result; + child.SetEventIndex(m_child_number); + if (m_enable_simplified_callbacks) { + CallWithJExceptionWrapper("JEventUnfolder::Unfold", [&](){ + result = Unfold(parent.GetEventNumber(), child.GetEventNumber(), m_child_number); + }); } else { - throw JException("Component needs to be initialized and not finalized before Unfold can be called"); + CallWithJExceptionWrapper("JEventUnfolder::Unfold", [&](){ + result = Unfold(parent, child, m_child_number); + }); } - } - catch (JException& ex) { - ex.plugin_name = m_plugin_name; - if (ex.component_name.empty()) { - ex.component_name = m_type_name; + for (auto* output : m_outputs) { + output->InsertCollection(child); } - throw ex; - } - catch (std::exception& e) { - auto ex = JException("Exception in JEventUnfolder::DoUnfold(): %s", e.what()); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; + m_child_number += 1; + if (result == Result::NextChildNextParent || result == Result::KeepChildNextParent) { + m_child_number = 0; + } + return result; } - catch (...) { - auto ex = JException("Exception in JEventUnfolder::DoUnfold()"); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; + else { + throw JException("Component needs to be initialized and not finalized before Unfold can be called"); } } void DoFinish() { - try { - std::lock_guard lock(m_mutex); - if (m_status != Status::Finalized) { + std::lock_guard lock(m_mutex); + if (m_status != Status::Finalized) { + CallWithJExceptionWrapper("JEventUnfolder::Finish", [&](){ Finish(); - m_status = Status::Finalized; - } - } - catch (JException& ex) { - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; - } - catch (...) { - auto ex = JException("Unknown exception in JEventUnfolder::Finish()"); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; + }); + m_status = Status::Finalized; } } }; diff --git a/src/libraries/JANA/JMultifactory.cc b/src/libraries/JANA/JMultifactory.cc index 4a5842248..39c7d9f8e 100644 --- a/src/libraries/JANA/JMultifactory.cc +++ b/src/libraries/JANA/JMultifactory.cc @@ -17,71 +17,49 @@ void JMultifactory::Execute(const std::shared_ptr& event) { #endif if (m_status == Status::Uninitialized) { - try { + CallWithJExceptionWrapper("JMultifactory::Init", [&](){ Init(); - m_status = Status::Initialized; - } - catch(std::exception &e) { - // Rethrow as a JException so that we can add context information - throw JException(e.what()); - } + }); + m_status = Status::Initialized; } auto run_number = event->GetRunNumber(); if (m_last_run_number == -1) { // This is the very first run - try { + CallWithJExceptionWrapper("JMultifactory::BeginRun", [&](){ BeginRun(event); - m_last_run_number = run_number; - } - catch(std::exception &e) { - // Rethrow as a JException so that we can add context information - throw JException(e.what()); - } + }); + m_last_run_number = run_number; } else if (m_last_run_number != run_number) { // This is a later run, and it has changed - try { + CallWithJExceptionWrapper("JMultifactory::EndRun", [&](){ EndRun(); - } - catch(std::exception &e) { - // Rethrow as a JException so that we can add context information - throw JException(e.what()); - } - try { + }); + CallWithJExceptionWrapper("JMultifactory::BeginRun", [&](){ BeginRun(event); - m_last_run_number = run_number; - } - catch(std::exception &e) { - // Rethrow as a JException so that we can add context information - throw JException(e.what()); - } + }); + m_last_run_number = run_number; } - try { + CallWithJExceptionWrapper("JMultifactory::Process", [&](){ Process(event); - } - catch(std::exception &e) { - // Rethrow as a JException so that we can add context information - throw JException(e.what()); - } + }); } void JMultifactory::Release() { std::lock_guard lock(m_mutex); - try { - // Only call Finish() if we actually initialized - // Only call Finish() once - if (m_status == Status::Initialized) { + // Only call Finish() if we actually initialized + // Only call Finish() once + if (m_status == Status::Initialized) { + CallWithJExceptionWrapper("JMultifactory::Finish", [&](){ Finish(); - m_status = Status::Finalized; - } - } - catch(std::exception &e) { - // Rethrow as a JException so that we can add context information - throw JException(e.what()); + }); + m_status = Status::Finalized; } } + JFactorySet* JMultifactory::GetHelpers() { return &mHelpers; } + From 8741aeae62a43f67692878514fb272f785bf4e42 Mon Sep 17 00:00:00 2001 From: Nathan Brei Date: Thu, 2 May 2024 16:50:19 -0400 Subject: [PATCH 3/9] Add separate "callback_name" field to JException Putting the callback name in the exception message was making the messages very long and obscuring the important part --- src/libraries/JANA/JException.h | 9 +++++++-- src/libraries/JANA/Omni/JComponent.h | 7 +++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/libraries/JANA/JException.h b/src/libraries/JANA/JException.h index 02180a795..124684525 100644 --- a/src/libraries/JANA/JException.h +++ b/src/libraries/JANA/JException.h @@ -46,8 +46,8 @@ struct JException : public std::exception { /// Convenience method for formatting complete error data inline friend std::ostream& operator<<(std::ostream& os, JException const& ex) { os << "Exception: " << ex.message << std::endl; - if (ex.plugin_name.length() != 0) { - os << " Plugin: " << ex.plugin_name << std::endl; + if (ex.callback_name.length() != 0) { + os << " Callback: " << ex.callback_name << std::endl; } if (ex.component_name.length() != 0) { os << " Component: " << ex.component_name << std::endl; @@ -56,6 +56,9 @@ struct JException : public std::exception { os << " Factory name: " << ex.factory_name << std::endl; os << " Factory tag: " << ex.factory_tag << std::endl; } + if (ex.plugin_name.length() != 0) { + os << " Plugin: " << ex.plugin_name << std::endl; + } if (ex.stacktrace.length() != 0 && ex.show_stacktrace) { os << " Backtrace:" << std::endl << std::endl << ex.stacktrace; } @@ -65,6 +68,8 @@ struct JException : public std::exception { std::string message; std::string plugin_name; std::string component_name; + std::string callback_name; + std::string component_prefix; std::string factory_name; std::string factory_tag; std::string stacktrace; diff --git a/src/libraries/JANA/Omni/JComponent.h b/src/libraries/JANA/Omni/JComponent.h index ea51f60b2..3e499f945 100644 --- a/src/libraries/JANA/Omni/JComponent.h +++ b/src/libraries/JANA/Omni/JComponent.h @@ -120,18 +120,21 @@ inline void JComponent::CallWithJExceptionWrapper(std::string func_name, F func) catch (JException& ex) { if (ex.plugin_name.empty()) ex.plugin_name = m_plugin_name; if (ex.component_name.empty()) ex.component_name = m_type_name; + if (ex.callback_name.empty()) ex.callback_name = func_name; throw ex; } catch (std::exception& e) { - auto ex = JException("Exception in %s: %s", func_name.c_str(), e.what()); + auto ex = JException(e.what()); ex.nested_exception = std::current_exception(); + ex.callback_name = func_name; ex.plugin_name = m_plugin_name; ex.component_name = m_type_name; throw ex; } catch (...) { - auto ex = JException("Unknown exception in %s", func_name.c_str()); + auto ex = JException("Unknown exception"); ex.nested_exception = std::current_exception(); + ex.callback_name = func_name; ex.plugin_name = m_plugin_name; ex.component_name = m_type_name; throw ex; From cace1ad62c5f4958dfe31f43e0466f5ce5b38ba9 Mon Sep 17 00:00:00 2001 From: Nathan Brei Date: Fri, 3 May 2024 12:28:33 -0400 Subject: [PATCH 4/9] JService uses CallWithJExceptionWrapper --- src/libraries/JANA/JService.cc | 39 ++++++++++------------------------ 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/src/libraries/JANA/JService.cc b/src/libraries/JANA/JService.cc index 5438d1ba7..0a66f258c 100644 --- a/src/libraries/JANA/JService.cc +++ b/src/libraries/JANA/JService.cc @@ -8,34 +8,17 @@ void JService::DoInit(JServiceLocator* sl) { std::lock_guard lock(m_mutex); if (this->m_status != Status::Uninitialized) return; - try { - for (auto* parameter : m_parameters) { - parameter->Configure(*(m_app->GetJParameterManager()), m_prefix); - } - for (auto* service : m_services) { - service->Init(GetApplication()); // TODO: This badly needs to be renamed. Maybe Fetch? - } - this->acquire_services(sl); - this->Init(); - this->m_status = Status::Initialized; - } - catch (JException& ex) { - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; - } - catch (std::exception& e){ - auto ex = JException("Exception in JService::DoInit(): %s", e.what()); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; + + for (auto* parameter : m_parameters) { + parameter->Configure(*(m_app->GetJParameterManager()), m_prefix); } - catch (...) { - auto ex = JException("Unknown exception in JService::DoInit()"); - ex.nested_exception = std::current_exception(); - ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; - throw ex; + + for (auto* service : m_services) { + service->Init(GetApplication()); // TODO: This badly needs to be renamed. Maybe Fetch? } + + CallWithJExceptionWrapper("JService::acquire_services", [&](){ this->acquire_services(sl); }); + CallWithJExceptionWrapper("JService::Init", [&](){ this->Init(); }); + + this->m_status = Status::Initialized; } From 808fd9dd93312987e8e7df7e24d3e6ac09764230 Mon Sep 17 00:00:00 2001 From: Nathan Brei Date: Fri, 3 May 2024 12:32:44 -0400 Subject: [PATCH 5/9] Rename JException metadata Now uses (function_name, type_name, instance_name, plugin_name) which make sense for all components --- src/libraries/JANA/JEventSource.h | 4 +- src/libraries/JANA/JException.h | 26 +++++------ src/libraries/JANA/JFactory.cc | 67 +++++++++++++++------------- src/libraries/JANA/JMultifactory.h | 30 ++++++++----- src/libraries/JANA/Omni/JComponent.h | 15 ++++--- 5 files changed, 79 insertions(+), 63 deletions(-) diff --git a/src/libraries/JANA/JEventSource.h b/src/libraries/JANA/JEventSource.h index 424c50dcc..45d1113ed 100644 --- a/src/libraries/JANA/JEventSource.h +++ b/src/libraries/JANA/JEventSource.h @@ -300,7 +300,9 @@ class JEventSource : public jana::omni::JComponent, public jana::omni::JHasOutpu else if (rs == RETURN_STATUS::kERROR || rs == RETURN_STATUS::kUNKNOWN) { JException ex ("JEventSource threw RETURN_STATUS::kERROR or kUNKNOWN"); ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; + ex.type_name = m_type_name; + ex.function_name = "JEventSource::GetEvent"; + ex.instance_name = m_resource_name; throw ex; } else { diff --git a/src/libraries/JANA/JException.h b/src/libraries/JANA/JException.h index 124684525..9c013a1c5 100644 --- a/src/libraries/JANA/JException.h +++ b/src/libraries/JANA/JException.h @@ -45,19 +45,19 @@ struct JException : public std::exception { /// Convenience method for formatting complete error data inline friend std::ostream& operator<<(std::ostream& os, JException const& ex) { - os << "Exception: " << ex.message << std::endl; - if (ex.callback_name.length() != 0) { - os << " Callback: " << ex.callback_name << std::endl; + os << "JException" << std::endl; + os << " Message: " << ex.message << std::endl; + if (ex.function_name.length() != 0) { + os << " Function: " << ex.function_name << std::endl; } - if (ex.component_name.length() != 0) { - os << " Component: " << ex.component_name << std::endl; + if (ex.type_name.length() != 0) { + os << " Class: " << ex.type_name << std::endl; } - if (ex.factory_name.length() != 0) { - os << " Factory name: " << ex.factory_name << std::endl; - os << " Factory tag: " << ex.factory_tag << std::endl; + if (ex.instance_name.length() != 0) { + os << " Instance: " << ex.instance_name << std::endl; } if (ex.plugin_name.length() != 0) { - os << " Plugin: " << ex.plugin_name << std::endl; + os << " Plugin: " << ex.plugin_name << std::endl; } if (ex.stacktrace.length() != 0 && ex.show_stacktrace) { os << " Backtrace:" << std::endl << std::endl << ex.stacktrace; @@ -67,11 +67,9 @@ struct JException : public std::exception { std::string message; std::string plugin_name; - std::string component_name; - std::string callback_name; - std::string component_prefix; - std::string factory_name; - std::string factory_tag; + std::string type_name; + std::string function_name; + std::string instance_name; std::string stacktrace; std::exception_ptr nested_exception; bool show_stacktrace=true; diff --git a/src/libraries/JANA/JFactory.cc b/src/libraries/JANA/JFactory.cc index d3c412c47..aa99f289a 100644 --- a/src/libraries/JANA/JFactory.cc +++ b/src/libraries/JANA/JFactory.cc @@ -18,28 +18,29 @@ void JFactory::Create(const std::shared_ptr& event) { mStatus = Status::Unprocessed; } catch (JException& ex) { + std::string instanceName = mTag.empty() ? mObjectName : mObjectName + ":" + mTag; + if (ex.function_name.empty()) ex.function_name = "JFactory::Init"; + if (ex.type_name.empty()) ex.type_name = mFactoryName; + if (ex.instance_name.empty()) ex.instance_name = instanceName; if (ex.plugin_name.empty()) ex.plugin_name = mPluginName; - if (ex.component_name.empty()) ex.component_name = mFactoryName; - if (ex.factory_name.empty()) ex.factory_name = mFactoryName; - if (ex.factory_tag.empty()) ex.factory_tag = mTag; throw ex; } catch (std::exception& e) { auto ex = JException("Exception in JFactoryT::Init(): %s", e.what()); ex.nested_exception = std::current_exception(); + ex.function_name = "JFactory::Init"; + ex.type_name = mFactoryName; + ex.instance_name = mTag.empty() ? mObjectName : mObjectName + ":" + mTag; ex.plugin_name = mPluginName; - ex.component_name = mFactoryName; - ex.factory_name = mFactoryName; - ex.factory_tag = mTag; throw ex; } catch (...) { - auto ex = JException("Unknown exception in JFactoryT::Init()"); + auto ex = JException("Unknown exception"); ex.nested_exception = std::current_exception(); + ex.function_name = "JFactory::Init"; + ex.type_name = mFactoryName; + ex.instance_name = mTag.empty() ? mObjectName : mObjectName + ":" + mTag; ex.plugin_name = mPluginName; - ex.component_name = mFactoryName; - ex.factory_name = mFactoryName; - ex.factory_tag = mTag; throw ex; } } @@ -66,56 +67,58 @@ void JFactory::Create(const std::shared_ptr& event) { } } catch (JException& ex) { + std::string instanceName = mTag.empty() ? mObjectName : mObjectName + ":" + mTag; + if (ex.function_name.empty()) ex.function_name = "JFactory::BeginRun/ChangeRun/EndRun("; + if (ex.type_name.empty()) ex.type_name = mFactoryName; + if (ex.instance_name.empty()) ex.instance_name = instanceName; if (ex.plugin_name.empty()) ex.plugin_name = mPluginName; - if (ex.component_name.empty()) ex.component_name = mFactoryName; - if (ex.factory_name.empty()) ex.factory_name = mFactoryName; - if (ex.factory_tag.empty()) ex.factory_tag = mTag; throw ex; } catch (std::exception& e) { - auto ex = JException("Exception in JFactory::BeginRun/ChangeRun/EndRun(): %s", e.what()); + auto ex = JException(e.what()); ex.nested_exception = std::current_exception(); + ex.function_name = "JFactory::BeginRun/ChangeRun/EndRun"; + ex.type_name = mFactoryName; + ex.instance_name = mTag.empty() ? mObjectName : mObjectName + ":" + mTag; ex.plugin_name = mPluginName; - ex.component_name = mFactoryName; - ex.factory_name = mFactoryName; - ex.factory_tag = mTag; throw ex; } catch (...) { - auto ex = JException("Unknown exception in JFactory::BeginRun/ChangeRun/EndRun()"); + auto ex = JException("Unknown exception"); ex.nested_exception = std::current_exception(); + ex.function_name = "JFactory::BeginRun/ChangeRun/EndRun"; + ex.type_name = mFactoryName; + ex.instance_name = mTag.empty() ? mObjectName : mObjectName + ":" + mTag; ex.plugin_name = mPluginName; - ex.component_name = mFactoryName; - ex.factory_name = mFactoryName; - ex.factory_tag = mTag; throw ex; } try { Process(event); } catch (JException& ex) { + std::string instanceName = mTag.empty() ? mObjectName : mObjectName + ":" + mTag; + if (ex.function_name.empty()) ex.function_name = "JFactory::Process"; + if (ex.type_name.empty()) ex.type_name = mFactoryName; + if (ex.instance_name.empty()) ex.instance_name = instanceName; if (ex.plugin_name.empty()) ex.plugin_name = mPluginName; - if (ex.component_name.empty()) ex.component_name = mFactoryName; - if (ex.factory_name.empty()) ex.factory_name = mFactoryName; - if (ex.factory_tag.empty()) ex.factory_tag = mTag; throw ex; } catch (std::exception& e) { - auto ex = JException("Exception in JFactory::Process(): %s", e.what()); + auto ex = JException(e.what()); ex.nested_exception = std::current_exception(); + ex.function_name = "JFactory::Process"; + ex.type_name = mFactoryName; + ex.instance_name = mTag.empty() ? mObjectName : mObjectName + ":" + mTag; ex.plugin_name = mPluginName; - ex.component_name = mFactoryName; - ex.factory_name = mFactoryName; - ex.factory_tag = mTag; throw ex; } catch (...) { - auto ex = JException("Unknown exception in JFactory::Process()"); + auto ex = JException("Unknown exception"); ex.nested_exception = std::current_exception(); + ex.function_name = "JFactory::Process"; + ex.type_name = mFactoryName; + ex.instance_name = mTag.empty() ? mObjectName : mObjectName + ":" + mTag; ex.plugin_name = mPluginName; - ex.component_name = mFactoryName; - ex.factory_name = mFactoryName; - ex.factory_tag = mTag; throw ex; } mStatus = Status::Processed; diff --git a/src/libraries/JANA/JMultifactory.h b/src/libraries/JANA/JMultifactory.h index ffb7912d8..a5de848e5 100644 --- a/src/libraries/JANA/JMultifactory.h +++ b/src/libraries/JANA/JMultifactory.h @@ -150,8 +150,10 @@ void JMultifactory::SetData(std::string tag, std::vector data) { JFactoryT* helper = mHelpers.GetFactory(tag); if (helper == nullptr) { auto ex = JException("JMultifactory: Attempting to SetData() without corresponding DeclareOutput()"); - ex.factory_name = m_type_name; - ex.factory_tag = m_prefix; + ex.function_name = "JMultifactory::SetData"; + ex.type_name = m_type_name; + ex.instance_name = m_prefix; + ex.plugin_name = m_plugin_name; throw ex; } #ifdef JANA2_HAVE_PODIO @@ -187,15 +189,19 @@ void JMultifactory::SetCollection(std::string tag, typename JFactoryPodioT::C JFactoryT* helper = mHelpers.GetFactory(tag); if (helper == nullptr) { auto ex = JException("JMultifactory: Attempting to SetData() without corresponding DeclareOutput()"); - ex.factory_name = m_type_name; - ex.factory_tag = m_prefix; + ex.function_name = "JMultifactory::SetCollection"; + ex.type_name = m_type_name; + ex.instance_name = m_prefix; + ex.plugin_name = m_plugin_name; throw ex; } auto* typed = dynamic_cast*>(helper); if (typed == nullptr) { auto ex = JException("JMultifactory: Helper needs to be a JFactoryPodioT (this shouldn't be reachable)"); - ex.factory_name = m_type_name; - ex.factory_tag = m_prefix; + ex.function_name = "JMultifactory::SetCollection"; + ex.type_name = m_type_name; + ex.instance_name = m_prefix; + ex.plugin_name = m_plugin_name; throw ex; } @@ -208,15 +214,19 @@ void JMultifactory::SetCollection(std::string tag, std::unique_ptr* helper = mHelpers.GetFactory(tag); if (helper == nullptr) { auto ex = JException("JMultifactory: Attempting to SetData() without corresponding DeclareOutput()"); - ex.factory_name = m_type_name; - ex.factory_tag = m_prefix; + ex.function_name = "JMultifactory::SetCollection"; + ex.type_name = m_type_name; + ex.instance_name = m_prefix; + ex.plugin_name = m_plugin_name; throw ex; } auto* typed = dynamic_cast*>(helper); if (typed == nullptr) { auto ex = JException("JMultifactory: Helper needs to be a JFactoryPodioT (this shouldn't be reachable)"); - ex.factory_name = m_type_name; - ex.factory_tag = m_prefix; + ex.function_name = "JMultifactory::SetCollection"; + ex.type_name = m_type_name; + ex.instance_name = m_prefix; + ex.plugin_name = m_plugin_name; throw ex; } diff --git a/src/libraries/JANA/Omni/JComponent.h b/src/libraries/JANA/Omni/JComponent.h index 3e499f945..e88629a53 100644 --- a/src/libraries/JANA/Omni/JComponent.h +++ b/src/libraries/JANA/Omni/JComponent.h @@ -118,25 +118,28 @@ inline void JComponent::CallWithJExceptionWrapper(std::string func_name, F func) func(); } catch (JException& ex) { + if (ex.function_name.empty()) ex.function_name = func_name; + if (ex.type_name.empty()) ex.type_name = m_type_name; + if (ex.instance_name.empty()) ex.instance_name = m_prefix; if (ex.plugin_name.empty()) ex.plugin_name = m_plugin_name; - if (ex.component_name.empty()) ex.component_name = m_type_name; - if (ex.callback_name.empty()) ex.callback_name = func_name; throw ex; } catch (std::exception& e) { auto ex = JException(e.what()); ex.nested_exception = std::current_exception(); - ex.callback_name = func_name; + ex.function_name = func_name; + ex.type_name = m_type_name; + ex.instance_name = m_prefix; ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; throw ex; } catch (...) { auto ex = JException("Unknown exception"); ex.nested_exception = std::current_exception(); - ex.callback_name = func_name; + ex.function_name = func_name; + ex.type_name = m_type_name; + ex.instance_name = m_prefix; ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; throw ex; } } From f2f340b918d690a04ba6e6bf341ea73892428630 Mon Sep 17 00:00:00 2001 From: Nathan Brei Date: Fri, 3 May 2024 15:09:55 -0400 Subject: [PATCH 6/9] JException displays wrapped exception type Addresses issue #277. --- src/libraries/JANA/JException.h | 8 +++++- src/libraries/JANA/JFactory.cc | 7 +++++ src/libraries/JANA/Omni/JComponent.h | 3 +++ src/libraries/JANA/Utils/JAutoActivator.cc | 1 + src/libraries/JANA/Utils/JTypeInfo.h | 14 ++++++++-- .../Components/JEventProcessorTests.cc | 23 ++++++++++++++++ .../unit_tests/Components/JFactoryTests.cc | 26 +++++++++++++++++++ 7 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/libraries/JANA/JException.h b/src/libraries/JANA/JException.h index 9c013a1c5..bc4e5a9f4 100644 --- a/src/libraries/JANA/JException.h +++ b/src/libraries/JANA/JException.h @@ -46,7 +46,12 @@ struct JException : public std::exception { /// Convenience method for formatting complete error data inline friend std::ostream& operator<<(std::ostream& os, JException const& ex) { os << "JException" << std::endl; - os << " Message: " << ex.message << std::endl; + if (ex.exception_type.length() != 0) { + os << " Type: " << ex.exception_type << std::endl; + } + if (ex.message.length() != 0) { + os << " Message: " << ex.message << std::endl; + } if (ex.function_name.length() != 0) { os << " Function: " << ex.function_name << std::endl; } @@ -65,6 +70,7 @@ struct JException : public std::exception { return os; } + std::string exception_type; std::string message; std::string plugin_name; std::string type_name; diff --git a/src/libraries/JANA/JFactory.cc b/src/libraries/JANA/JFactory.cc index aa99f289a..5c14d8ab4 100644 --- a/src/libraries/JANA/JFactory.cc +++ b/src/libraries/JANA/JFactory.cc @@ -4,6 +4,7 @@ #include #include +#include void JFactory::Create(const std::shared_ptr& event) { @@ -27,6 +28,7 @@ void JFactory::Create(const std::shared_ptr& event) { } catch (std::exception& e) { auto ex = JException("Exception in JFactoryT::Init(): %s", e.what()); + ex.exception_type = JTypeInfo::demangle_current_exception_type(); ex.nested_exception = std::current_exception(); ex.function_name = "JFactory::Init"; ex.type_name = mFactoryName; @@ -36,6 +38,7 @@ void JFactory::Create(const std::shared_ptr& event) { } catch (...) { auto ex = JException("Unknown exception"); + ex.exception_type = JTypeInfo::demangle_current_exception_type(); ex.nested_exception = std::current_exception(); ex.function_name = "JFactory::Init"; ex.type_name = mFactoryName; @@ -76,6 +79,7 @@ void JFactory::Create(const std::shared_ptr& event) { } catch (std::exception& e) { auto ex = JException(e.what()); + ex.exception_type = JTypeInfo::demangle_current_exception_type(); ex.nested_exception = std::current_exception(); ex.function_name = "JFactory::BeginRun/ChangeRun/EndRun"; ex.type_name = mFactoryName; @@ -85,6 +89,7 @@ void JFactory::Create(const std::shared_ptr& event) { } catch (...) { auto ex = JException("Unknown exception"); + ex.exception_type = JTypeInfo::demangle_current_exception_type(); ex.nested_exception = std::current_exception(); ex.function_name = "JFactory::BeginRun/ChangeRun/EndRun"; ex.type_name = mFactoryName; @@ -105,6 +110,7 @@ void JFactory::Create(const std::shared_ptr& event) { } catch (std::exception& e) { auto ex = JException(e.what()); + ex.exception_type = JTypeInfo::demangle_current_exception_type(); ex.nested_exception = std::current_exception(); ex.function_name = "JFactory::Process"; ex.type_name = mFactoryName; @@ -114,6 +120,7 @@ void JFactory::Create(const std::shared_ptr& event) { } catch (...) { auto ex = JException("Unknown exception"); + ex.exception_type = JTypeInfo::demangle_current_exception_type(); ex.nested_exception = std::current_exception(); ex.function_name = "JFactory::Process"; ex.type_name = mFactoryName; diff --git a/src/libraries/JANA/Omni/JComponent.h b/src/libraries/JANA/Omni/JComponent.h index e88629a53..30891298d 100644 --- a/src/libraries/JANA/Omni/JComponent.h +++ b/src/libraries/JANA/Omni/JComponent.h @@ -6,6 +6,7 @@ #pragma once #include #include +#include namespace jana { namespace omni { @@ -126,6 +127,7 @@ inline void JComponent::CallWithJExceptionWrapper(std::string func_name, F func) } catch (std::exception& e) { auto ex = JException(e.what()); + ex.exception_type = JTypeInfo::demangle_current_exception_type(); ex.nested_exception = std::current_exception(); ex.function_name = func_name; ex.type_name = m_type_name; @@ -135,6 +137,7 @@ inline void JComponent::CallWithJExceptionWrapper(std::string func_name, F func) } catch (...) { auto ex = JException("Unknown exception"); + ex.exception_type = JTypeInfo::demangle_current_exception_type(); ex.nested_exception = std::current_exception(); ex.function_name = func_name; ex.type_name = m_type_name; diff --git a/src/libraries/JANA/Utils/JAutoActivator.cc b/src/libraries/JANA/Utils/JAutoActivator.cc index e986e8f6e..37fdd7e15 100644 --- a/src/libraries/JANA/Utils/JAutoActivator.cc +++ b/src/libraries/JANA/Utils/JAutoActivator.cc @@ -7,6 +7,7 @@ JAutoActivator::JAutoActivator() { SetTypeName("JAutoActivator"); + SetCallbackStyle(CallbackStyle::ExpertMode); } void JAutoActivator::AddAutoActivatedFactory(string factory_name, string factory_tag) { diff --git a/src/libraries/JANA/Utils/JTypeInfo.h b/src/libraries/JANA/Utils/JTypeInfo.h index 39762c401..57a0c12f1 100644 --- a/src/libraries/JANA/Utils/JTypeInfo.h +++ b/src/libraries/JANA/Utils/JTypeInfo.h @@ -27,11 +27,11 @@ struct is_serializable() << s template -std::string demangle(void) { +std::string demangle() { /// Return the demangled name (if available) for the type the template /// is based. Call it like this: - /// cout << GetDemangledName() << endl; + /// cout << demangle() << endl; int status = -1; auto cstr = abi::__cxa_demangle(typeid(T).name(), NULL, NULL, &status); std::string type(cstr); @@ -41,6 +41,16 @@ std::string demangle(void) { } +inline std::string demangle_current_exception_type() { + + int status = -1; + auto cstr = abi::__cxa_demangle(abi::__cxa_current_exception_type()->name(), NULL, NULL, &status); + std::string type(cstr); + free(cstr); + if (status != 0) type = abi::__cxa_current_exception_type()->name(); + return type; +} + /// Macro for conveniently turning a variable name into a string. This is used by JObject::Summarize /// in order to play nicely with refactoring tools. Because the symbol is picked up by the /// preprocessor and not the compiler, no demangling is necessary. diff --git a/src/programs/unit_tests/Components/JEventProcessorTests.cc b/src/programs/unit_tests/Components/JEventProcessorTests.cc index cba55e739..71d836602 100644 --- a/src/programs/unit_tests/Components/JEventProcessorTests.cc +++ b/src/programs/unit_tests/Components/JEventProcessorTests.cc @@ -60,3 +60,26 @@ TEST_CASE("JEventProcessor_ExpertMode_ProcessCount") { REQUIRE(destroy_count == 1); } +struct MyExceptingProcessor : public JEventProcessor { + void Process(const std::shared_ptr&) override { + throw std::runtime_error("Mystery!"); + } +}; + +TEST_CASE("JEventProcessor_Exception") { + JApplication app; + app.Add(new JEventSource); + app.Add(new MyExceptingProcessor); + bool found_throw = false; + try { + app.Run(); + } + catch(JException& ex) { + REQUIRE(ex.function_name == "JEventProcessor::Process"); + REQUIRE(ex.message == "Mystery!"); + REQUIRE(ex.exception_type == "std::runtime_error"); + found_throw = true; + } + REQUIRE(found_throw == true); + +} diff --git a/src/programs/unit_tests/Components/JFactoryTests.cc b/src/programs/unit_tests/Components/JFactoryTests.cc index 159ee8ae7..4c165ff04 100644 --- a/src/programs/unit_tests/Components/JFactoryTests.cc +++ b/src/programs/unit_tests/Components/JFactoryTests.cc @@ -221,3 +221,29 @@ TEST_CASE("JFactoryTests") { } } + +struct MyExceptingFactory : public JFactoryT { + void Process(const std::shared_ptr&) override { + throw std::runtime_error("Weird mystery!"); + } +}; + +TEST_CASE("JFactory_Exception") { + JApplication app; + app.Add(new JEventSource); + app.Add(new JFactoryGeneratorT()); + app.SetParameterValue("autoactivate", "JFactoryTestDummyObject"); + bool found_throw = false; + try { + app.Run(); + } + catch(JException& ex) { + LOG << ex << LOG_END; + REQUIRE(ex.function_name == "JFactory::Process"); + REQUIRE(ex.message == "Weird mystery!"); + REQUIRE(ex.exception_type == "std::runtime_error"); + found_throw = true; + } + REQUIRE(found_throw == true); +} + From 371939ff6447b9e9fe1a966712ecaa1c3bd0e7df Mon Sep 17 00:00:00 2001 From: Nathan Brei Date: Mon, 6 May 2024 22:06:25 -0400 Subject: [PATCH 7/9] JFactory inherits from JComponent --- src/libraries/JANA/JFactory.cc | 128 +++--------------- src/libraries/JANA/JFactory.h | 37 ++--- src/libraries/JANA/JFactoryGenerator.h | 1 + src/libraries/JANA/Omni/JComponentFwd.h | 2 +- .../unit_tests/Components/JFactoryTests.cc | 2 + 5 files changed, 33 insertions(+), 137 deletions(-) diff --git a/src/libraries/JANA/JFactory.cc b/src/libraries/JANA/JFactory.cc index 5c14d8ab4..48a450f53 100644 --- a/src/libraries/JANA/JFactory.cc +++ b/src/libraries/JANA/JFactory.cc @@ -9,43 +9,12 @@ void JFactory::Create(const std::shared_ptr& event) { - // Make sure that we have a valid JApplication before attempting to call callbacks - if (mApp == nullptr) mApp = event->GetJApplication(); - auto run_number = event->GetRunNumber(); + // We need this for JMultifactoryHelper. Eventually it should go away + SetApplication(event->GetJApplication()); if (mStatus == Status::Uninitialized) { - try { - Init(); - mStatus = Status::Unprocessed; - } - catch (JException& ex) { - std::string instanceName = mTag.empty() ? mObjectName : mObjectName + ":" + mTag; - if (ex.function_name.empty()) ex.function_name = "JFactory::Init"; - if (ex.type_name.empty()) ex.type_name = mFactoryName; - if (ex.instance_name.empty()) ex.instance_name = instanceName; - if (ex.plugin_name.empty()) ex.plugin_name = mPluginName; - throw ex; - } - catch (std::exception& e) { - auto ex = JException("Exception in JFactoryT::Init(): %s", e.what()); - ex.exception_type = JTypeInfo::demangle_current_exception_type(); - ex.nested_exception = std::current_exception(); - ex.function_name = "JFactory::Init"; - ex.type_name = mFactoryName; - ex.instance_name = mTag.empty() ? mObjectName : mObjectName + ":" + mTag; - ex.plugin_name = mPluginName; - throw ex; - } - catch (...) { - auto ex = JException("Unknown exception"); - ex.exception_type = JTypeInfo::demangle_current_exception_type(); - ex.nested_exception = std::current_exception(); - ex.function_name = "JFactory::Init"; - ex.type_name = mFactoryName; - ex.instance_name = mTag.empty() ? mObjectName : mObjectName + ":" + mTag; - ex.plugin_name = mPluginName; - throw ex; - } + CallWithJExceptionWrapper("JFactory::Init", [&](){ Init(); }); + mStatus = Status::Unprocessed; } if (TestFactoryFlag(REGENERATE) && (mStatus == Status::Inserted)) { @@ -54,80 +23,21 @@ void JFactory::Create(const std::shared_ptr& event) { } if (mStatus == Status::Unprocessed) { - try { - if (mPreviousRunNumber == -1) { - // This is the very first run - ChangeRun(event); - BeginRun(event); - mPreviousRunNumber = run_number; - } - else if (mPreviousRunNumber != run_number) { - // This is a later run, and it has changed - EndRun(); - ChangeRun(event); - BeginRun(event); - mPreviousRunNumber = run_number; - } - } - catch (JException& ex) { - std::string instanceName = mTag.empty() ? mObjectName : mObjectName + ":" + mTag; - if (ex.function_name.empty()) ex.function_name = "JFactory::BeginRun/ChangeRun/EndRun("; - if (ex.type_name.empty()) ex.type_name = mFactoryName; - if (ex.instance_name.empty()) ex.instance_name = instanceName; - if (ex.plugin_name.empty()) ex.plugin_name = mPluginName; - throw ex; - } - catch (std::exception& e) { - auto ex = JException(e.what()); - ex.exception_type = JTypeInfo::demangle_current_exception_type(); - ex.nested_exception = std::current_exception(); - ex.function_name = "JFactory::BeginRun/ChangeRun/EndRun"; - ex.type_name = mFactoryName; - ex.instance_name = mTag.empty() ? mObjectName : mObjectName + ":" + mTag; - ex.plugin_name = mPluginName; - throw ex; - } - catch (...) { - auto ex = JException("Unknown exception"); - ex.exception_type = JTypeInfo::demangle_current_exception_type(); - ex.nested_exception = std::current_exception(); - ex.function_name = "JFactory::BeginRun/ChangeRun/EndRun"; - ex.type_name = mFactoryName; - ex.instance_name = mTag.empty() ? mObjectName : mObjectName + ":" + mTag; - ex.plugin_name = mPluginName; - throw ex; - } - try { - Process(event); - } - catch (JException& ex) { - std::string instanceName = mTag.empty() ? mObjectName : mObjectName + ":" + mTag; - if (ex.function_name.empty()) ex.function_name = "JFactory::Process"; - if (ex.type_name.empty()) ex.type_name = mFactoryName; - if (ex.instance_name.empty()) ex.instance_name = instanceName; - if (ex.plugin_name.empty()) ex.plugin_name = mPluginName; - throw ex; - } - catch (std::exception& e) { - auto ex = JException(e.what()); - ex.exception_type = JTypeInfo::demangle_current_exception_type(); - ex.nested_exception = std::current_exception(); - ex.function_name = "JFactory::Process"; - ex.type_name = mFactoryName; - ex.instance_name = mTag.empty() ? mObjectName : mObjectName + ":" + mTag; - ex.plugin_name = mPluginName; - throw ex; - } - catch (...) { - auto ex = JException("Unknown exception"); - ex.exception_type = JTypeInfo::demangle_current_exception_type(); - ex.nested_exception = std::current_exception(); - ex.function_name = "JFactory::Process"; - ex.type_name = mFactoryName; - ex.instance_name = mTag.empty() ? mObjectName : mObjectName + ":" + mTag; - ex.plugin_name = mPluginName; - throw ex; - } + auto run_number = event->GetRunNumber(); + if (mPreviousRunNumber == -1) { + // This is the very first run + CallWithJExceptionWrapper("JFactory::ChangeRun", [&](){ ChangeRun(event); }); + CallWithJExceptionWrapper("JFactory::BeginRun", [&](){ BeginRun(event); }); + mPreviousRunNumber = run_number; + } + else if (mPreviousRunNumber != run_number) { + // This is a later run, and it has changed + CallWithJExceptionWrapper("JFactory::EndRun", [&](){ EndRun(); }); + CallWithJExceptionWrapper("JFactory::ChangeRun", [&](){ ChangeRun(event); }); + CallWithJExceptionWrapper("JFactory::BeginRun", [&](){ BeginRun(event); }); + mPreviousRunNumber = run_number; + } + CallWithJExceptionWrapper("JFactory::Process", [&](){ Process(event); }); mStatus = Status::Processed; mCreationStatus = CreationStatus::Created; } diff --git a/src/libraries/JANA/JFactory.h b/src/libraries/JANA/JFactory.h index e2cc0a69d..37042d928 100644 --- a/src/libraries/JANA/JFactory.h +++ b/src/libraries/JANA/JFactory.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -25,7 +26,7 @@ class JEvent; class JObject; class JApplication; -class JFactory { +class JFactory : public jana::omni::JComponent { public: enum class Status {Uninitialized, Unprocessed, Processed, Inserted}; @@ -40,7 +41,11 @@ class JFactory { }; JFactory(std::string aName, std::string aTag = "") - : mObjectName(std::move(aName)), mTag(std::move(aTag)), mStatus(Status::Uninitialized) {}; + : mObjectName(std::move(aName)), + mTag(std::move(aTag)), + mStatus(Status::Uninitialized) { + SetPrefix(aTag.empty() ? mObjectName : mObjectName + ":" + mTag); + }; virtual ~JFactory() = default; @@ -49,8 +54,7 @@ class JFactory { std::string GetTag() const { return mTag; } std::string GetObjectName() const { return mObjectName; } - std::string GetFactoryName() const { return mFactoryName; } - std::string GetPluginName() const { return mPluginName; } + std::string GetFactoryName() const { return m_type_name; } Status GetStatus() const { return mStatus; } CreationStatus GetCreationStatus() const { return mCreationStatus; } JCallGraphRecorder::JDataOrigin GetInsertOrigin() const { return m_insert_origin; } ///< If objects were placed here by JEvent::Insert() this records whether that call was made from a source or factory. @@ -62,8 +66,8 @@ class JFactory { void SetTag(std::string tag) { mTag = std::move(tag); } void SetObjectName(std::string objectName) { mObjectName = std::move(objectName); } - void SetFactoryName(std::string factoryName) { mFactoryName = std::move(factoryName); } - void SetPluginName(std::string pluginName) { mPluginName = std::move(pluginName); } + void SetFactoryName(std::string factoryName) { SetTypeName(factoryName); } + void SetStatus(Status status){ mStatus = status; } void SetCreationStatus(CreationStatus status){ mCreationStatus = status; } void SetInsertOrigin(JCallGraphRecorder::JDataOrigin origin) { m_insert_origin = origin; } ///< Called automatically by JEvent::Insert() to records whether that call was made by a source or factory. @@ -170,23 +174,9 @@ class JFactory { /// use JFactory::GetAs(). virtual void Create(const std::shared_ptr& event); - /// JApplication setter. This is meant to be used under the hood. - void SetApplication(JApplication* app) { mApp = app; } - - /// JApplication getter. This is meant to be called by user-defined JFactories which need to - /// acquire parameter values or services from JFactory::Init() - JApplication* GetApplication() { return mApp; } - - virtual void Set(const std::vector &data) = 0; virtual void Insert(JObject *data) = 0; - // Meant to be called by user in constructor - void SetLevel(JEventLevel level) { mLevel = level; } - - // Meant to be called by JANA - JEventLevel GetLevel() { return mLevel; } - protected: @@ -194,19 +184,12 @@ class JFactory { std::string mTag; uint32_t mFlags = WRITE_TO_OUTPUT; int32_t mPreviousRunNumber = -1; - JApplication* mApp = nullptr; std::unordered_map> mUpcastVTable; mutable Status mStatus = Status::Uninitialized; mutable JCallGraphRecorder::JDataOrigin m_insert_origin = JCallGraphRecorder::ORIGIN_NOT_AVAILABLE; // (see note at top of JCallGraphRecorder.h) CreationStatus mCreationStatus = CreationStatus::NotCreatedYet; - - // Common to components - JEventLevel mLevel = JEventLevel::PhysicsEvent; - std::string mPluginName; - std::string mFactoryName; - mutable std::mutex mMutex; }; // Because C++ doesn't support templated virtual functions, we implement our own dispatch table, mUpcastVTable. diff --git a/src/libraries/JANA/JFactoryGenerator.h b/src/libraries/JANA/JFactoryGenerator.h index 739465681..e0de26916 100644 --- a/src/libraries/JANA/JFactoryGenerator.h +++ b/src/libraries/JANA/JFactoryGenerator.h @@ -61,6 +61,7 @@ class JFactoryGeneratorT : public JFactoryGenerator { } factory->SetFactoryName(JTypeInfo::demangle()); factory->SetPluginName(GetPluginName()); + factory->SetApplication(GetApplication()); factory_set->Add(factory); } }; diff --git a/src/libraries/JANA/Omni/JComponentFwd.h b/src/libraries/JANA/Omni/JComponentFwd.h index d23562721..0d1975916 100644 --- a/src/libraries/JANA/Omni/JComponentFwd.h +++ b/src/libraries/JANA/Omni/JComponentFwd.h @@ -68,7 +68,7 @@ struct JComponent { // --------------------- // Meant to be called by JANA // --------------------- - std::string GetPrefix() { return m_prefix; } + std::string GetPrefix() { return m_prefix.empty() ? m_type_name : m_prefix; } JEventLevel GetLevel() { return m_level; } diff --git a/src/programs/unit_tests/Components/JFactoryTests.cc b/src/programs/unit_tests/Components/JFactoryTests.cc index 4c165ff04..2c7501e72 100644 --- a/src/programs/unit_tests/Components/JFactoryTests.cc +++ b/src/programs/unit_tests/Components/JFactoryTests.cc @@ -242,6 +242,8 @@ TEST_CASE("JFactory_Exception") { REQUIRE(ex.function_name == "JFactory::Process"); REQUIRE(ex.message == "Weird mystery!"); REQUIRE(ex.exception_type == "std::runtime_error"); + REQUIRE(ex.type_name == "MyExceptingFactory"); + REQUIRE(ex.instance_name == "JFactoryTestDummyObject"); found_throw = true; } REQUIRE(found_throw == true); From 11674a7cb01b47669bce8efb4fc397f8d3685fae Mon Sep 17 00:00:00 2001 From: Nathan Brei Date: Tue, 7 May 2024 00:14:07 -0400 Subject: [PATCH 8/9] Inject logger into JFactory --- src/libraries/JANA/JFactoryGenerator.h | 1 + .../unit_tests/Components/JFactoryTests.cc | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/libraries/JANA/JFactoryGenerator.h b/src/libraries/JANA/JFactoryGenerator.h index e0de26916..b15c859eb 100644 --- a/src/libraries/JANA/JFactoryGenerator.h +++ b/src/libraries/JANA/JFactoryGenerator.h @@ -62,6 +62,7 @@ class JFactoryGeneratorT : public JFactoryGenerator { factory->SetFactoryName(JTypeInfo::demangle()); factory->SetPluginName(GetPluginName()); factory->SetApplication(GetApplication()); + factory->SetLogger(GetApplication()->template GetService()->get_logger(factory->GetPrefix())); factory_set->Add(factory); } }; diff --git a/src/programs/unit_tests/Components/JFactoryTests.cc b/src/programs/unit_tests/Components/JFactoryTests.cc index 2c7501e72..436edbc79 100644 --- a/src/programs/unit_tests/Components/JFactoryTests.cc +++ b/src/programs/unit_tests/Components/JFactoryTests.cc @@ -249,3 +249,22 @@ TEST_CASE("JFactory_Exception") { REQUIRE(found_throw == true); } +struct MyLoggedFactory : public JFactoryT { + MyLoggedFactory() { + SetPrefix("myfac"); + } + void Process(const std::shared_ptr&) override { + LOG_INFO(GetLogger()) << "Process ran!" << LOG_END; + REQUIRE(GetLogger().level == JLogger::Level::DEBUG); + } +}; +TEST_CASE("JFactory_Logger") { + JApplication app; + app.Add(new JEventSource); + app.Add(new JFactoryGeneratorT()); + app.SetParameterValue("log:debug", "myfac"); + app.SetParameterValue("jana:nevents", "1"); + app.SetParameterValue("autoactivate", "JFactoryTestDummyObject"); + app.Run(); +} + From 8a74887223f8972aa073f2df039eb3b04ee619d4 Mon Sep 17 00:00:00 2001 From: Nathan Brei Date: Wed, 8 May 2024 01:02:50 -0400 Subject: [PATCH 9/9] JEventPool is now responsible for setting JEvent app ptr Previously, it was the JEventSource, which doesn't work in the case of TimesliceExample, because PhysicsEvents come straight from the pool. --- src/libraries/JANA/JEventSource.h | 1 - src/libraries/JANA/JFactory.cc | 3 ++- src/libraries/JANA/Omni/JComponentFwd.h | 7 ++++++- src/libraries/JANA/Services/JComponentManager.cc | 1 + 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/libraries/JANA/JEventSource.h b/src/libraries/JANA/JEventSource.h index 45d1113ed..c2c740c70 100644 --- a/src/libraries/JANA/JEventSource.h +++ b/src/libraries/JANA/JEventSource.h @@ -192,7 +192,6 @@ class JEventSource : public jana::omni::JComponent, public jana::omni::JHasOutpu // We configure the event event->SetEventNumber(m_event_count); // Default event number to event count - event->SetJApplication(m_app); event->SetJEventSource(this); event->SetSequential(false); event->GetJCallGraphRecorder()->Reset(); diff --git a/src/libraries/JANA/JFactory.cc b/src/libraries/JANA/JFactory.cc index 48a450f53..baa3f6865 100644 --- a/src/libraries/JANA/JFactory.cc +++ b/src/libraries/JANA/JFactory.cc @@ -10,7 +10,8 @@ void JFactory::Create(const std::shared_ptr& event) { // We need this for JMultifactoryHelper. Eventually it should go away - SetApplication(event->GetJApplication()); + auto app = event->GetJApplication(); + if (app != nullptr) SetApplication(app); if (mStatus == Status::Uninitialized) { CallWithJExceptionWrapper("JFactory::Init", [&](){ Init(); }); diff --git a/src/libraries/JANA/Omni/JComponentFwd.h b/src/libraries/JANA/Omni/JComponentFwd.h index 0d1975916..f73bfe8f9 100644 --- a/src/libraries/JANA/Omni/JComponentFwd.h +++ b/src/libraries/JANA/Omni/JComponentFwd.h @@ -85,7 +85,12 @@ struct JComponent { return m_status; } - void SetApplication(JApplication* app) { m_app = app; } + void SetApplication(JApplication* app) { + if (app == nullptr) { + throw JException("Attempting to set a null JApplication pointer!"); + } + m_app = app; + } void SetLogger(JLogger logger) { m_logger = logger; } diff --git a/src/libraries/JANA/Services/JComponentManager.cc b/src/libraries/JANA/Services/JComponentManager.cc index b4c724b7c..5642e8415 100644 --- a/src/libraries/JANA/Services/JComponentManager.cc +++ b/src/libraries/JANA/Services/JComponentManager.cc @@ -108,6 +108,7 @@ void JComponentManager::configure_event(JEvent& event) { event.SetFactorySet(factory_set); event.SetDefaultTags(m_default_tags); event.GetJCallGraphRecorder()->SetEnabled(m_enable_call_graph_recording); + event.SetJApplication(GetApplication()); }