You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by fg...@apache.org on 2021/09/15 15:40:30 UTC

[nifi-minifi-cpp] branch main updated: MINIFICPP-1471 - Build extensions as dynamic libraries and dynamically load them

This is an automated email from the ASF dual-hosted git repository.

fgerlits pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git


The following commit(s) were added to refs/heads/main by this push:
     new 63a2e57  MINIFICPP-1471 - Build extensions as dynamic libraries and dynamically load them
63a2e57 is described below

commit 63a2e574cdbf856722ded7b799eefc3c77fe4f8b
Author: Adam Debreceni <ad...@apache.org>
AuthorDate: Thu Jul 22 11:14:44 2021 +0200

    MINIFICPP-1471 - Build extensions as dynamic libraries and dynamically load them
    
    Signed-off-by: Ferenc Gerlits <fg...@gmail.com>
    
    This closes #1138
---
 CMakeLists.txt                                     |  15 -
 CONFIGURE.md                                       |   3 +
 Extensions.md                                      | 134 ++----
 cmake/BuildTests.cmake                             |  26 +-
 cmake/BundledAwsSdkCpp.cmake                       |  16 +-
 cmake/BundledLibCoAP.cmake                         |   2 +-
 cmake/BundledLibXml2.cmake                         |   2 +-
 cmake/Extensions.cmake                             |  22 +-
 cmake/WholeArchive.cmake                           |  19 +
 conf/minifi.properties                             |   3 +
 controller/CMakeLists.txt                          |  22 +-
 controller/Controller.h                            |   2 +-
 encrypt-config/CMakeLists.txt                      |  11 +-
 encrypt-config/tests/CMakeLists.txt                |   5 +-
 extensions/aws/AWSLoader.h                         |  84 ----
 extensions/aws/CMakeLists.txt                      |  11 +-
 .../controllerservices/AWSCredentialsService.cpp   |   4 +
 .../aws/controllerservices/AWSCredentialsService.h |   3 -
 extensions/aws/processors/DeleteS3Object.cpp       |   4 +
 extensions/aws/processors/DeleteS3Object.h         |   2 -
 extensions/aws/processors/FetchS3Object.cpp        |   4 +
 extensions/aws/processors/FetchS3Object.h          |   2 -
 extensions/aws/processors/ListS3.cpp               |   3 +
 extensions/aws/processors/ListS3.h                 |   2 -
 extensions/aws/processors/PutS3Object.cpp          |   3 +
 extensions/aws/processors/PutS3Object.h            |   2 -
 extensions/azure/AzureLoader.cpp                   |  28 --
 extensions/azure/AzureLoader.h                     |  68 ---
 extensions/azure/CMakeLists.txt                    |   6 +-
 .../AzureStorageCredentialsService.cpp             |   4 +
 .../AzureStorageCredentialsService.h               |   3 -
 .../azure/processors/PutAzureBlobStorage.cpp       |   3 +
 extensions/azure/processors/PutAzureBlobStorage.h  |   2 -
 extensions/bustache/ApplyTemplate.cpp              |   4 +
 extensions/bustache/ApplyTemplate.h                |   4 -
 extensions/bustache/CMakeLists.txt                 |   3 +-
 extensions/bustache/TemplateLoader.cpp             |  28 --
 extensions/bustache/TemplateLoader.h               |  65 ---
 extensions/civetweb/CMakeLists.txt                 |   3 +-
 extensions/civetweb/processors/ListenHTTP.cpp      |   8 +
 extensions/civetweb/processors/ListenHTTP.h        |  33 +-
 extensions/civetweb/tests/CMakeLists.txt           |   6 +-
 extensions/coap/CMakeLists.txt                     |   3 +-
 extensions/coap/COAPLoader.cpp                     |  20 +-
 extensions/coap/COAPLoader.h                       |  91 ----
 .../coap/controllerservice/CoapConnector.cpp       |   3 +
 extensions/coap/controllerservice/CoapConnector.h  |   1 +
 extensions/coap/protocols/CoapC2Protocol.cpp       |   3 +
 extensions/coap/protocols/CoapC2Protocol.h         |   1 +
 extensions/coap/tests/CMakeLists.txt               |   8 +-
 extensions/coap/tests/CoapIntegrationBase.h        |   3 +-
 extensions/expression-language/CMakeLists.txt      |   3 +-
 .../ExpressionContextBuilder.cpp                   |   3 +
 .../expression-language/ExpressionLoader.cpp       |  27 --
 extensions/expression-language/ExpressionLoader.h  |  70 ---
 .../expression-language/tests/CMakeLists.txt       |   8 +-
 extensions/gps/CMakeLists.txt                      |   4 +-
 extensions/gps/GetGPS.cpp                          |   3 +
 extensions/gps/GetGPS.h                            |   3 -
 extensions/gps/GetGPSLoader.h                      |  67 ---
 extensions/gps/GetGpsLoader.cpp                    |  29 --
 extensions/http-curl/CMakeLists.txt                |   3 +-
 extensions/http-curl/HTTPCurlLoader.cpp            |  26 +-
 extensions/http-curl/HTTPCurlLoader.h              | 104 -----
 extensions/http-curl/client/HTTPClient.cpp         |   3 +
 extensions/http-curl/processors/InvokeHTTP.cpp     |   5 +
 extensions/http-curl/processors/InvokeHTTP.h       |  76 ++-
 extensions/http-curl/protocols/AgentPrinter.cpp    |   3 +
 extensions/http-curl/protocols/AgentPrinter.h      |   3 -
 extensions/http-curl/protocols/RESTReceiver.cpp    |   5 +
 extensions/http-curl/protocols/RESTReceiver.h      |   3 -
 extensions/http-curl/protocols/RESTSender.cpp      |   3 +
 extensions/http-curl/protocols/RESTSender.h        |   2 -
 extensions/http-curl/sitetosite/HTTPProtocol.cpp   |   3 +
 extensions/http-curl/tests/C2PauseResumeTest.cpp   |   2 +-
 extensions/http-curl/tests/CMakeLists.txt          |  12 +-
 .../tests/ControllerServiceIntegrationTests.cpp    |   5 +-
 extensions/http-curl/tests/VerifyInvokeHTTP.h      |   2 +-
 extensions/jni/CMakeLists.txt                      |   3 +-
 extensions/jni/ClassRegistrar.h                    |   1 -
 extensions/jni/ExecuteJavaControllerService.cpp    |   3 +
 extensions/jni/ExecuteJavaControllerService.h      |   3 -
 extensions/jni/ExecuteJavaProcessor.cpp            |   3 +
 extensions/jni/ExecuteJavaProcessor.h              |   3 -
 extensions/jni/JNILoader.cpp                       |  20 +-
 extensions/jni/JNILoader.h                         |  80 ----
 extensions/jni/JVMCreator.cpp                      |   3 +
 extensions/jni/jvm/JavaControllerService.cpp       |   3 +
 extensions/jni/jvm/JavaControllerService.h         |   3 -
 extensions/jni/jvm/JniProcessContext.h             |  10 +-
 extensions/jni/jvm/NarClassLoader.h                |   3 +-
 extensions/libarchive/ArchiveLoader.h              |  81 ----
 extensions/libarchive/BinFiles.cpp                 |   3 +
 extensions/libarchive/BinFiles.h                   |  38 +-
 extensions/libarchive/CMakeLists.txt               |   3 +-
 extensions/libarchive/CompressContent.cpp          |   3 +
 extensions/libarchive/CompressContent.h            |  22 +-
 extensions/libarchive/FocusArchiveEntry.cpp        |   5 +
 extensions/libarchive/FocusArchiveEntry.h          |  12 +-
 extensions/libarchive/ManipulateArchive.cpp        |   3 +
 extensions/libarchive/ManipulateArchive.h          |  27 +-
 extensions/libarchive/MergeContent.cpp             |   5 +
 extensions/libarchive/MergeContent.h               |  27 +-
 extensions/libarchive/UnfocusArchiveEntry.cpp      |   3 +
 extensions/libarchive/UnfocusArchiveEntry.h        |   3 -
 extensions/librdkafka/CMakeLists.txt               |   3 +-
 extensions/librdkafka/ConsumeKafka.cpp             |   5 +
 extensions/librdkafka/ConsumeKafka.h               |  40 +-
 extensions/librdkafka/PublishKafka.cpp             |   4 +
 extensions/librdkafka/PublishKafka.h               |  64 ++-
 extensions/librdkafka/RdKafkaLoader.cpp            |  29 --
 extensions/librdkafka/RdKafkaLoader.h              |  67 ---
 extensions/librdkafka/docker_tests/CMakeLists.txt  |   2 +-
 extensions/librdkafka/tests/CMakeLists.txt         |   6 +-
 extensions/mqtt/CMakeLists.txt                     |   3 +-
 extensions/mqtt/MQTTLoader.cpp                     |  29 --
 extensions/mqtt/MQTTLoader.h                       |  88 ----
 .../controllerservice/MQTTControllerService.cpp    |   3 +
 .../mqtt/controllerservice/MQTTControllerService.h |   1 -
 extensions/mqtt/processors/ConsumeMQTT.cpp         |   3 +
 extensions/mqtt/processors/ConsumeMQTT.h           |   3 -
 extensions/mqtt/processors/ConvertBase.h           |   1 -
 extensions/mqtt/processors/ConvertHeartBeat.cpp    |   3 +
 extensions/mqtt/processors/ConvertHeartBeat.h      |   1 -
 extensions/mqtt/processors/ConvertJSONAck.cpp      |   4 +
 extensions/mqtt/processors/ConvertJSONAck.h        |   1 -
 extensions/mqtt/processors/ConvertUpdate.cpp       |   3 +
 extensions/mqtt/processors/PublishMQTT.cpp         |   3 +
 extensions/mqtt/processors/PublishMQTT.h           |   3 -
 extensions/mqtt/protocol/MQTTC2Protocol.cpp        |   3 +
 extensions/mqtt/protocol/MQTTC2Protocol.h          |   1 +
 extensions/opc/CMakeLists.txt                      |   3 +-
 extensions/opc/include/fetchopc.h                  |   3 -
 extensions/opc/include/putopc.h                    |   3 -
 extensions/opc/src/fetchopc.cpp                    |   2 +
 extensions/opc/src/putopc.cpp                      |   2 +
 extensions/opencv/CMakeLists.txt                   |   2 +-
 extensions/opencv/CaptureRTSPFrame.cpp             |   3 +
 extensions/opencv/CaptureRTSPFrame.h               |  20 +-
 extensions/opencv/MotionDetector.cpp               |   3 +
 extensions/opencv/MotionDetector.h                 |   3 -
 extensions/opencv/OpenCVLoader.cpp                 |  23 +-
 extensions/opencv/OpenCVLoader.h                   |  85 ----
 extensions/opencv/tests/CMakeLists.txt             |   4 +-
 extensions/openwsman/CMakeLists.txt                |   4 +-
 .../SourceInitiatedSubscriptionListener.cpp        |   4 +
 .../SourceInitiatedSubscriptionListener.h          |   4 -
 extensions/pcap/CMakeLists.txt                     |   3 +-
 extensions/pcap/CapturePacket.cpp                  |   5 +
 extensions/pcap/CapturePacket.h                    |   5 -
 extensions/pcap/PcapLoader.cpp                     |  29 --
 extensions/pcap/PcapLoader.h                       |  66 ---
 extensions/pdh/CMakeLists.txt                      |   3 +-
 extensions/pdh/PerformanceDataMonitor.cpp          |   3 +
 extensions/pdh/PerformanceDataMonitor.h            |  14 +-
 extensions/pdh/tests/CMakeLists.txt                |   4 +-
 extensions/rocksdb-repos/CMakeLists.txt            |   3 +-
 .../rocksdb-repos/DatabaseContentRepository.cpp    |   3 +
 extensions/rocksdb-repos/FlowFileRepository.cpp    |   3 +
 extensions/rocksdb-repos/ProvenanceRepository.cpp  |   7 +
 extensions/rocksdb-repos/ProvenanceRepository.h    |   1 +
 extensions/rocksdb-repos/RocksDBLoader.cpp         |  29 --
 extensions/rocksdb-repos/RocksDBLoader.h           |  85 ----
 .../RocksDbPersistableKeyValueStoreService.cpp     |   4 +
 .../RocksDbPersistableKeyValueStoreService.h       |   2 -
 extensions/script/CMakeLists.txt                   |  33 +-
 extensions/script/ExecuteScript.cpp                |   7 +
 extensions/script/ExecuteScript.h                  |   7 -
 .../script/python/ExecutePythonProcessor.cpp       |   8 +
 extensions/script/python/ExecutePythonProcessor.h  |  18 +-
 extensions/script/python/PyProcCreator.cpp         |  23 -
 extensions/script/python/PythonCreator.cpp         |  47 --
 extensions/script/python/PythonCreator.h           | 148 +++---
 .../{PyProcCreator.h => PythonObjectFactory.h}     |  27 --
 extensions/script/python/PythonScriptEngine.cpp    |   1 -
 extensions/script/pythonloader/PyProcLoader.cpp    |  22 +-
 extensions/script/pythonloader/PyProcLoader.h      |  68 ---
 extensions/sensors/CMakeLists.txt                  |   3 +-
 extensions/sensors/GetEnvironmentalSensors.cpp     |   3 +
 extensions/sensors/GetEnvironmentalSensors.h       |   3 -
 extensions/sensors/GetMovementSensors.cpp          |   4 +
 extensions/sensors/GetMovementSensors.h            |   3 -
 extensions/sensors/SensorBase.h                    |   1 -
 extensions/sensors/SensorLoader.h                  |  69 ---
 extensions/sftp/CMakeLists.txt                     |   3 +-
 extensions/sftp/SFTPLoader.cpp                     |  19 +-
 extensions/sftp/SFTPLoader.h                       |  81 ----
 extensions/sftp/processors/FetchSFTP.cpp           |   3 +
 extensions/sftp/processors/FetchSFTP.h             |   3 -
 extensions/sftp/processors/ListSFTP.cpp            |   6 +
 extensions/sftp/processors/ListSFTP.h              |   6 -
 extensions/sftp/processors/PutSFTP.cpp             |   3 +
 extensions/sftp/processors/PutSFTP.h               |   3 -
 extensions/sftp/tests/CMakeLists.txt               |  12 +-
 extensions/sftp/tests/FetchSFTPTests.cpp           |   4 +-
 extensions/sftp/tests/ListSFTPTests.cpp            |   2 +-
 extensions/sftp/tests/PutSFTPTests.cpp             |  16 +-
 extensions/sftp/tests/tools/CMakeLists.txt         |   4 +-
 extensions/sftp/tests/tools/SFTPTestServer.cpp     |   9 +-
 extensions/sftp/tests/tools/SFTPTestServer.h       |   2 +
 extensions/sql/CMakeLists.txt                      |   5 +-
 extensions/sql/SQLLoader.cpp                       |  29 --
 extensions/sql/SQLLoader.h                         |  77 ---
 extensions/sql/processors/ExecuteSQL.cpp           |   3 +
 extensions/sql/processors/ExecuteSQL.h             |  15 +-
 extensions/sql/processors/FlowFileSource.h         |  10 +-
 extensions/sql/processors/PutSQL.cpp               |   3 +
 extensions/sql/processors/PutSQL.h                 |   9 +-
 extensions/sql/processors/QueryDatabaseTable.cpp   |   2 +
 extensions/sql/processors/QueryDatabaseTable.h     |  25 +-
 extensions/sql/services/DatabaseService.h          |   2 +-
 extensions/sql/services/ODBCConnector.cpp          |   3 +
 extensions/sql/services/ODBCConnector.h            |   3 -
 extensions/standard-processors/CMakeLists.txt      |   3 +-
 .../UnorderedMapKeyValueStoreService.cpp           |   3 +
 .../controllers/UnorderedMapKeyValueStoreService.h |   3 -
 ...UnorderedMapPersistableKeyValueStoreService.cpp |   3 +
 .../UnorderedMapPersistableKeyValueStoreService.h  |   2 -
 .../processors/AppendHostInfo.cpp                  |   3 +
 .../processors/AppendHostInfo.h                    |  14 +-
 .../processors/AttributesToJSON.cpp                |   4 +
 .../processors/AttributesToJSON.h                  |  16 +-
 .../processors/ExecuteProcess.cpp                  |   6 +
 .../processors/ExecuteProcess.h                    |   4 -
 .../standard-processors/processors/ExtractText.cpp |   3 +
 .../standard-processors/processors/ExtractText.h   |  24 +-
 .../processors/GenerateFlowFile.cpp                |   3 +
 .../processors/GenerateFlowFile.h                  |  20 +-
 .../standard-processors/processors/GetFile.cpp     |   3 +
 .../standard-processors/processors/GetFile.h       |  30 +-
 .../standard-processors/processors/GetTCP.cpp      |   3 +
 extensions/standard-processors/processors/GetTCP.h |  27 +-
 .../standard-processors/processors/HashContent.cpp |   3 +
 .../standard-processors/processors/HashContent.h   |  16 +-
 .../processors/ListenSyslog.cpp                    |   9 +
 .../standard-processors/processors/ListenSyslog.h  |   8 -
 .../processors/LogAttribute.cpp                    |   3 +
 .../standard-processors/processors/LogAttribute.h  |  24 +-
 .../standard-processors/processors/PutFile.cpp     |   3 +
 .../standard-processors/processors/PutFile.h       |  20 +-
 .../processors/RetryFlowFile.cpp                   |  10 +
 .../standard-processors/processors/RetryFlowFile.h |  36 +-
 .../processors/RouteOnAttribute.cpp                |   4 +
 .../processors/RouteOnAttribute.h                  |   3 -
 .../standard-processors/processors/TailFile.cpp    |   8 +
 .../standard-processors/processors/TailFile.h      |  31 +-
 .../processors/UpdateAttribute.cpp                 |   5 +
 .../processors/UpdateAttribute.h                   |   4 -
 .../standard-processors/tests/CMakeLists.txt       |  14 +-
 .../TLSClientSocketSupportedProtocolsTest.cpp      |   1 +
 .../TLSServerSocketSupportedProtocolsTest.cpp      |   1 +
 .../tests/unit/ClassLoaderTests.cpp                |   3 -
 .../tests/unit/ManifestTests.cpp                   |   2 +-
 .../tests/unit/ProcessorTests.cpp                  |   4 +
 extensions/systemd/CMakeLists.txt                  |   3 +-
 extensions/systemd/ConsumeJournald.cpp             |   4 +
 extensions/systemd/ConsumeJournald.h               |   4 -
 extensions/systemd/tests/CMakeLists.txt            |   4 +-
 extensions/tensorflow/CMakeLists.txt               |   3 +-
 extensions/tensorflow/TFApplyGraph.cpp             |   4 +
 extensions/tensorflow/TFApplyGraph.h               |   4 -
 extensions/tensorflow/TFConvertImageToTensor.cpp   |   2 +
 extensions/tensorflow/TFConvertImageToTensor.h     |   2 -
 extensions/tensorflow/TFExtractTopLabels.cpp       |   2 +
 extensions/tensorflow/TFExtractTopLabels.h         |   2 -
 extensions/usb-camera/CMakeLists.txt               |   3 +-
 extensions/usb-camera/GetUSBCamera.cpp             |   3 +
 extensions/usb-camera/GetUSBCamera.h               |   3 -
 extensions/windows-event-log/CMakeLists.txt        |   3 +-
 .../CollectorInitiatedSubscription.cpp             |   3 +
 .../CollectorInitiatedSubscription.h               |   2 -
 .../windows-event-log/ConsumeWindowsEventLog.cpp   |   3 +
 .../windows-event-log/ConsumeWindowsEventLog.h     |  37 +-
 extensions/windows-event-log/TailEventLog.cpp      |   5 +-
 extensions/windows-event-log/TailEventLog.h        |   1 -
 extensions/windows-event-log/tests/CMakeLists.txt  |   6 +-
 libminifi/CMakeLists.txt                           |  42 +-
 libminifi/include/FlowController.h                 |   7 +-
 libminifi/include/RemoteProcessorGroupPort.h       |  15 +-
 libminifi/include/agent/agent_docs.h               |   5 +-
 libminifi/include/agent/agent_version.h            |  15 +-
 libminifi/include/c2/ControllerSocketProtocol.h    |   3 -
 libminifi/include/c2/HeartbeatLogger.h             |   2 -
 libminifi/include/c2/triggers/FileUpdateTrigger.h  |   3 -
 .../controllers/LinuxPowerManagementService.h      |   3 -
 .../controllers/NetworkPrioritizerService.h        |  14 +-
 libminifi/include/controllers/SSLContextService.h  |  23 +-
 .../include/controllers/ThreadManagementService.h  |   1 -
 .../controllers/UpdatePolicyControllerService.h    |  13 +-
 .../AbstractAutoPersistingKeyValueStoreService.h   |   6 +-
 libminifi/include/core/ClassLoader.h               | 515 +++------------------
 libminifi/include/core/FlowConfiguration.h         |  54 +--
 libminifi/include/core/FlowFile.h                  |  19 +-
 libminifi/include/core/ObjectFactory.h             | 149 ++++++
 libminifi/include/core/Resource.h                  |  59 ++-
 libminifi/include/core/TypedValues.h               |   5 +-
 .../extension/DynamicLibrary.h}                    |  44 +-
 .../include/core/extension/Executable.h            |  28 +-
 libminifi/include/core/extension/Extension.h       | 104 +++++
 .../extension/ExtensionManager.h}                  |  38 +-
 .../HeartbeatLogger.h => core/extension/Module.h}  |  44 +-
 .../include/core/logging/LoggerConfiguration.h     |  10 +-
 libminifi/include/core/state/Value.h               |  15 +-
 .../include/core/state/nodes/AgentInformation.h    |  11 +-
 .../include/core/state/nodes/BuildInformation.h    |   4 -
 .../core/state/nodes/ConfigurationChecksums.h      |   3 -
 .../include/core/state/nodes/DeviceInformation.h   |  10 +-
 .../include/core/state/nodes/FlowInformation.h     |   4 -
 .../include/core/state/nodes/ProcessMetrics.h      |   4 -
 libminifi/include/core/state/nodes/StateMonitor.h  |   1 -
 libminifi/include/core/state/nodes/SystemMetrics.h |   3 -
 libminifi/include/sitetosite/SiteToSite.h          |   7 +-
 libminifi/include/utils/Enum.h                     |  49 +-
 .../include/utils/Export.h                         |  27 +-
 libminifi/include/utils/Macro.h                    |  67 +++
 libminifi/include/utils/file/FilePattern.h         | 117 +++++
 libminifi/include/utils/file/FileUtils.h           |  57 ++-
 libminifi/src/FlowController.cpp                   |  24 +-
 libminifi/src/ThreadedSchedulingAgent.cpp          |   2 +-
 .../src/agent/agent_docs.cpp                       |  20 +-
 libminifi/src/c2/ControllerSocketProtocol.cpp      |   3 +
 libminifi/src/c2/HeartbeatLogger.cpp               |   3 +
 libminifi/src/c2/triggers/FileUpdateTrigger.cpp    |   4 +
 .../controllers/LinuxPowerManagementService.cpp    |   4 +
 .../src/controllers/NetworkPrioritizerService.cpp  |   4 +
 libminifi/src/controllers/SSLContextService.cpp    |   3 +
 .../controllers/UpdatePolicyControllerService.cpp  |   5 +
 libminifi/src/core/ClassLoader.cpp                 |  61 +--
 libminifi/src/core/FlowConfiguration.cpp           |  34 ++
 libminifi/src/core/ProcessContextBuilder.cpp       |   3 +
 libminifi/src/core/extension/DynamicLibrary.cpp    | 195 ++++++++
 libminifi/src/core/extension/Extension.cpp         |  56 +++
 libminifi/src/core/extension/ExtensionManager.cpp  | 137 ++++++
 libminifi/src/core/extension/Module.cpp            |  84 ++++
 libminifi/src/core/logging/LoggerConfiguration.cpp |   9 +
 .../src/core/state/nodes/AgentInformation.cpp      |   3 +
 .../{AgentInformation.cpp => BuildInformation.cpp} |  20 +-
 .../core/state/nodes/ConfigurationChecksums.cpp    |   3 +
 .../src/core/state/nodes/DeviceInformation.cpp     |   3 +
 .../{AgentInformation.cpp => FlowInformation.cpp}  |  19 +-
 .../{AgentInformation.cpp => ProcessMetrics.cpp}   |  19 +-
 .../{AgentInformation.cpp => SystemMetrics.cpp}    |  19 +-
 libminifi/src/core/yaml/YamlConfiguration.cpp      |  15 -
 libminifi/src/utils/file/FilePattern.cpp           | 274 +++++++++++
 libminifi/test/KamikazeProcessor.cpp               |   3 +
 libminifi/test/KamikazeProcessor.h                 |   3 -
 libminifi/test/LogUtils.h                          |  55 +++
 libminifi/test/TestBase.cpp                        |   6 +-
 libminifi/test/TestBase.h                          |  34 +-
 libminifi/test/archive-tests/CMakeLists.txt        |   4 +-
 libminifi/test/aws-tests/CMakeLists.txt            |  10 +-
 libminifi/test/aws-tests/S3TestsFixture.h          |   7 -
 libminifi/test/azure-tests/CMakeLists.txt          |  10 +-
 libminifi/test/bustache-tests/CMakeLists.txt       |   4 +-
 libminifi/test/coap-tests/CMakeLists.txt           |   4 +-
 libminifi/test/flow-tests/CMakeLists.txt           |   4 +-
 libminifi/test/flow-tests/CustomProcessors.h       |   1 +
 libminifi/test/flow-tests/TestControllerWithFlow.h |   2 +-
 libminifi/test/gps-tests/CMakeLists.txt            |   4 +-
 libminifi/test/gps-tests/GPSTests.cpp              |   1 -
 libminifi/test/integration/IntegrationBase.h       |   2 +-
 .../test/integration/ProvenanceReportingTest.cpp   |   2 +-
 libminifi/test/jni-tests/CMakeLists.txt            |   4 +-
 libminifi/test/kafka-tests/CMakeLists.txt          |   4 +-
 libminifi/test/keyvalue-tests/CMakeLists.txt       |   4 +-
 libminifi/test/mqtt-tests/CMakeLists.txt           |   4 +-
 libminifi/test/pcap-tests/CMakeLists.txt           |   4 +-
 libminifi/test/persistence-tests/CMakeLists.txt    |   6 +-
 .../test/persistence-tests/PersistenceTests.cpp    |   4 +-
 libminifi/test/rocksdb-tests/CMakeLists.txt        |   4 +-
 libminifi/test/rocksdb-tests/RepoTests.cpp         |   2 +-
 libminifi/test/script-tests/CMakeLists.txt         |  12 +-
 .../script-tests/ExecutePythonProcessorTests.cpp   |   9 +-
 libminifi/test/sensors-tests/CMakeLists.txt        |   4 +-
 libminifi/test/sql-tests/CMakeLists.txt            |   6 +-
 libminifi/test/tensorflow-tests/CMakeLists.txt     |   4 +-
 libminifi/test/unit/FilePatternTests.cpp           | 249 ++++++++++
 libminifi/test/unit/MemoryUsageTest.cpp            |   4 +
 libminifi/test/unit/ProcessSessionTests.cpp        |   1 +
 libminifi/test/unit/ProvenanceTestHelper.h         |   2 +-
 libminifi/test/usb-camera-tests/CMakeLists.txt     |   4 +-
 main/AgentDocs.cpp                                 |   1 +
 main/CMakeLists.txt                                |  24 +-
 main/MiNiFiMain.cpp                                |   3 -
 nanofi/CMakeLists.txt                              |  21 +-
 nanofi/ecu/CMakeLists.txt                          |   6 +-
 nanofi/examples/CMakeLists.txt                     |   8 +-
 nanofi/include/cxx/CallbackProcessor.h             |   3 -
 nanofi/include/cxx/Instance.h                      |   3 +-
 nanofi/src/cxx/CallbackProcessor.cpp               |   4 +
 python/library/CMakeLists.txt                      |   8 +-
 python/library/python_lib.cpp                      |   4 +-
 thirdparty/aws-sdk-cpp/dll-export-injection.patch  |  52 +++
 thirdparty/aws-sdk-cpp/shutdown-fix.patch          |  12 +
 thirdparty/pcap++/3rdParty/LightPcapNg/Makefile    |   2 +-
 thirdparty/pcap++/Common++/Makefile                |   2 +-
 thirdparty/pcap++/Packet++/Makefile                |   4 +-
 thirdparty/pcap++/Pcap++/Makefile                  |   2 +-
 win_build_vs.bat                                   |   2 +-
 399 files changed, 3289 insertions(+), 3798 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index ee3053f..ca0b484 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -604,7 +604,6 @@ endif()
 
 if (ENABLE_ENCRYPT_CONFIG)
 	add_subdirectory(encrypt-config)
-	add_dependencies(encrypt-config minifi)
 endif()
 
 if (NOT DISABLE_CURL AND NOT DISABLE_CONTROLLER)
@@ -791,20 +790,6 @@ install(FILES LICENSE README.md NOTICE
 		DESTINATION .
 		COMPONENT bin)
 
-if(WIN32)
-	#preference is to use the exe type so that we have a solution that works well for cross compilation
-	#but that leaves the onus up to the developer, so until we can automate some of that build let's enforce
-	#the exe here temporarily
-	#TODO: Remove this and automate this step.
-	#install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/main/minifi.exe
-			#DESTINATION bin
-			#COMPONENT bin)
-else()
-	install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/main/minifi
-			DESTINATION bin
-			COMPONENT bin)
-endif()
-
 
 if (WIN32)
 	set(CPACK_GENERATOR "WIX")
diff --git a/CONFIGURE.md b/CONFIGURE.md
index 13c859d..58b015e 100644
--- a/CONFIGURE.md
+++ b/CONFIGURE.md
@@ -372,5 +372,8 @@ The MQTTController Service can be configured for MQTT connectivity and provide t
          Max Throughput: 1,024,1024
          Max Payload: 1,024,1024
 
+### Extension configuration
+To notify the agent which extensions it should load see [Loading extensions](Extensions.md#Loading extensions).
+
 ### JNI Functionality
 Please see the [JNI Configuration Guide](JNI.md).
diff --git a/Extensions.md b/Extensions.md
index 8ecca59..212de7e 100644
--- a/Extensions.md
+++ b/Extensions.md
@@ -16,108 +16,58 @@
 
 To enable all extensions for your platform, you may use -DENABLE_ALL=TRUE OR select the option to "Enable all Extensions" in the bootstrap script. [ReadMe](https://github.com/apache/nifi-minifi-cpp/#bootstrapping)
 
-# Extensions by example
-
-Extensions consist of modules that are conditionally built into your client. Reasons why you may wish to do this with your modules/processors
-
-  - Do not with to make dependencies required or the lack thereof is a known/expected runtime condition.
-  - You wish to allow users to exclude dependencies for a variety of reasons.
-
-# Extensions by example
-We've used HTTP-CURL as the first example. We've taken all libcURL runtime classes and placed them into an extensions folder 
-   - /extensions/http-curl
-   
-This folder contains a CMakeLists file so that we can conditionally build it. In the case with libcURL, if the user does not have curl installed OR they specify -DDISABLE_CURL=true in the cmake build, the extensions will not be built. In this case, when the extension is not built, C2 REST protocols, InvokeHTTP, and an HTTP Client implementation will not be included.
-
-Your CMAKE file should build a static library, that will be included into the run time. This must be added with your conditional to the libminifi CMAKE, along with a platform specific whole archive inclusion. Note that this will ensure that despite no direct linkage being found by the compiler, we will include the code so that we can dynamically find your code.
-
-# Including your extension in the build
-There is a new function that can be used in the root cmake to build and included your extension. An example is based on the LibArchive extension. The createExtension function has 8 possible arguments. The first five arguments are required.
-The first argument specifies the variable controlling the exclusion of this extension, followed by the variable that
-is used when including it into conditional statements. The third argument is the pretty name followed by the description of the extension and the extension directory. The first optional argument is the test directory, which must also contain a CMakeLists.txt file. The seventh argument can be a conditional variable that tells us whether or not to add a third party subdirectory specified by the final extension.
-
-In the lib archive example, we provide all arguments, but your extension may only need the first five and the the test folder. The seventh and eighth arguments must be included in tandem. 
-
-```cmake
-if ( NOT LibArchive_FOUND OR BUILD_LIBARCHIVE )
-	set(BUILD_TP "TRUE")
-endif()
-createExtension(DISABLE_LIBARCHIVE 
-				ARCHIVE-EXTENSIONS 
-				"ARCHIVE EXTENSIONS" 
-				"This Enables libarchive functionality including MergeContent, CompressContent, and (Un)FocusArchiveEntry" 
-				"extensions/libarchive"
-				"${TEST_DIR}/archive-tests"
-				BUILD_TP
-				"thirdparty/libarchive-3.3.2")
+# Extension internals
+Extensions are dynamic libraries loaded at runtime by the agent. An extension makes its 
+capabilities (classes) available to the system through registrars. Registration must happen in source files, not headers.
+
+``` C++
+// register user-facing classes as
+REGISTER_RESOURCE(InvokeHTTP, "An HTTP client processor which can interact with a configurable HTTP Endpoint. "
+    "The destination URL and HTTP Method are configurable. FlowFile attributes are converted to HTTP headers and the "
+    "FlowFile contents are included as the body of the request (if the HTTP Method is PUT, POST or PATCH).");
+
+// register internal resources as
+REGISTER_INTERNAL_RESOURCE(HTTPClient);
 ```
 
-It is advised that you also add your extension to bootstrap.sh as that is the suggested method of configuring MiNiFi C++
-  
-# C bindings
-To find your classes, you must adhere to a dlsym call back that adheres to the core::ObjectFactory class, like the one below. This object factory will return a list of classes, that we can instantiate through the class loader mechanism. Note that since we are including your code directly into our runtime, we will take care of dlopen and dlsym calls. A map from the class name to the object factory is kept in memory.
+Some extensions (e.g. `http-curl`) require initialization before use. 
+You need to create `init` and `deinit` functions and register them using `REGISTER_EXTENSION`.
 
 ```C++
-class __attribute__((visibility("default"))) HttpCurlObjectFactory : public core::ObjectFactory {
- public:
-  HttpCurlObjectFactory() {
-
-  }
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  virtual std::string getName() {
-    return "HttpCurlObjectFactory";
-  }
-
-  virtual std::string getClassName() {
-    return "HttpCurlObjectFactory";
-  }
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  virtual std::vector<std::string> getClassNames() {
-    std::vector<std::string> class_names;
-    class_names.push_back("RESTProtocol");
-    class_names.push_back("RESTReceiver");
-    class_names.push_back("RESTSender");
-    class_names.push_back("InvokeHTTP");
-    class_names.push_back("HTTPClient");
-    return class_names;
-  }
-
-  virtual std::unique_ptr<ObjectFactory> assign(const std::string &class_name) {
-    if (class_name == "RESTReceiver") {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::c2::RESTReceiver>());
-    } else if (class_name == "RESTSender") {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::c2::RESTSender>());
-    } else if (class_name == "InvokeHTTP") {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<processors::InvokeHTTP>());
-    } else if (class_name == "HTTPClient") {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<utils::HTTPClient>());
-    } else {
-      return nullptr;
-    }
-  }
-
-};
+static bool init(const core::extension::ExtensionConfig& /*config*/) override {
+  return curl_global_init(CURL_GLOBAL_DEFAULT) == CURLE_OK;
+}
 
-extern "C" {
-void *createHttpCurlFactory(void);
+static void deinit() override {
+  curl_global_cleanup();
 }
+
+REGISTER_EXTENSION("HttpCurlExtension", init, deinit);
 ```
 
-## Using your object factory function
-To use your C function, you must define the sequence "Class Loader Functions" in your YAML file under FlowController. This will indicate to the code that the factory function is to be called and we will create the mappings defined, above.
+If you don't use `REGISTER_EXTENSION`, the registered resources still become available, so make sure to register the extension if you need special initialization.
 
-Note that for the case of HTTP-CURL we have made it so that if libcURL exists and it is not disabled, the createHttpCurlFactory function is automatically loaded. To do this use the function FlowConfiguration::add_static_func -- this will add your function to the list of registered resources and will do so in a thread safe way. If you take this approach you cannot disable your library with an argument within the YAML file.
+# Loading extensions
 
+The agent will look for the `nifi.extension.path` property in the `minifi.properties` file to determine what extensions to load.
 
-## Common extension practices
+The property expects a comma separated list of paths.
+The paths support wildcards, specifically, a standalone `**` matches any number of nested directories, the `*` matches any number of characters in a single segment and `?` matches one single character in a segment.
+Relative paths are relative to the agent executable.
+```
+// This matches all files in the 'extensions' directory next to the directory the executable is in.
+nifi.extension.path=../extensions/*
+```
 
-Extensions should minimize dependencies that are dynamically linked. This means that you should statically link to dependencies when possible. You should verify that your resulting binary doesn't have system dependencies via ldd (in Linux) or dumpbbin /dependents on Microsoft Windows. 
+### Exlusion
+If you want to exclude some extensions from being loaded, without having to specify the rest, you can do so by prefixing the pattern with `!`.
+```
+// This loads all extensions but the gps extension. (the exact name differs by platform: dylib, dll, so)
+nifi.extension.path=../extensions/*,!../extensions/libminifi-gps.so
+```
 
-It is advised that you place your extension in bootstrap.sh to allow users a visual menu for enabling or disabling your extension. It should not be enabled by default unless discussed with the community at large. If there is reliance on specialized hardware you should perform as many compile time tests as possible to ensure your extension cannot be enabled. 
+You could even exclude some subdirectory and then re-include specific extensions/subdirectories in that.
+```
+// The last pattern that matches an extension will determine if that extension is loaded or not.
+nifi.extension.path=../extensions/**,!../extensions/private/*,../extension/private/my-cool-extension.dll
+```
diff --git a/cmake/BuildTests.cmake b/cmake/BuildTests.cmake
index 4bea79c..33b93b6 100644
--- a/cmake/BuildTests.cmake
+++ b/cmake/BuildTests.cmake
@@ -69,24 +69,23 @@ function(createTests testName)
 
   if (ENABLE_BINARY_DIFF)
     target_include_directories(${testName} SYSTEM BEFORE PRIVATE "${CMAKE_SOURCE_DIR}/thirdparty/bsdiff/")
-    endif(ENABLE_BINARY_DIFF)
+  endif(ENABLE_BINARY_DIFF)
 
-    if (Boost_FOUND)
-      target_include_directories(${testName} BEFORE PRIVATE "${Boost_INCLUDE_DIRS}")
-    endif()
-    target_link_libraries(${testName} ${CMAKE_DL_LIBS} ${TEST_BASE_LIB})
-    target_link_libraries(${testName} core-minifi yaml-cpp spdlog Threads::Threads)
-    if (NOT excludeBase)
-      target_wholearchive_library(${testName} minifi)
+  if (Boost_FOUND)
+    target_include_directories(${testName} BEFORE PRIVATE "${Boost_INCLUDE_DIRS}")
   endif()
+  target_link_libraries(${testName} ${CMAKE_DL_LIBS} ${TEST_BASE_LIB})
+  target_link_libraries(${testName} core-minifi yaml-cpp spdlog Threads::Threads)
   add_dependencies(${testName} minifiexe)
   if (ENABLE_NANOFI)
     add_dependencies(${testName} nanofi)
   endif()
   if (Boost_FOUND)
-    target_link_libraries(${testName} ${Boost_SYSTEM_LIBRARY})
-    target_link_libraries(${testName} ${Boost_FILESYSTEM_LIBRARY})
+      target_link_libraries(${testName} ${Boost_SYSTEM_LIBRARY})
+      target_link_libraries(${testName} ${Boost_FILESYSTEM_LIBRARY})
   endif()
+  target_compile_definitions(${testName} PRIVATE LOAD_EXTENSIONS)
+  set_target_properties(${testName} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
 endfunction()
 
 enable_testing(test)
@@ -133,9 +132,12 @@ if(NOT WIN32 AND ENABLE_NANOFI)
     target_include_directories(${testfilename} BEFORE PRIVATE "${CMAKE_SOURCE_DIR}/extensions/standard-processors/processors/")
     target_include_directories(${testfilename} BEFORE PRIVATE "${CMAKE_SOURCE_DIR}/libminifi/test")
     appendIncludes("${testfilename}")
-    target_link_libraries(${testfilename} ${CATCH_MAIN_LIB} ${TEST_BASE_LIB} nanofi Threads::Threads)
+    target_link_libraries(${testfilename} ${CATCH_MAIN_LIB} ${TEST_BASE_LIB} Threads::Threads)
+    target_wholearchive_library(${testfilename} nanofi)
+
+    createTests(${testfilename})
 
-    target_wholearchive_library(${testfilename} minifi-standard-processors)
+    target_link_libraries(${testfilename} minifi-standard-processors)
 
     MATH(EXPR UNIT_TEST_COUNT "${UNIT_TEST_COUNT}+1")
     add_test(NAME "${testfilename}" COMMAND "${testfilename}" WORKING_DIRECTORY ${TEST_DIR})
diff --git a/cmake/BundledAwsSdkCpp.cmake b/cmake/BundledAwsSdkCpp.cmake
old mode 100755
new mode 100644
index 706b02a..8960bf9
--- a/cmake/BundledAwsSdkCpp.cmake
+++ b/cmake/BundledAwsSdkCpp.cmake
@@ -16,8 +16,13 @@
 # under the License.
 
 function(use_bundled_libaws SOURCE_DIR BINARY_DIR)
-    set(PATCH_FILE "${SOURCE_DIR}/thirdparty/aws-sdk-cpp/c++20-compilation-fixes.patch")
-    set(AWS_SDK_CPP_PATCH_COMMAND "${Patch_EXECUTABLE}" -p1 -R -s -f --dry-run -i "${PATCH_FILE}" || "${Patch_EXECUTABLE}" -p1 -N -i "${PATCH_FILE}")
+    set(PATCH_FILE1 "${SOURCE_DIR}/thirdparty/aws-sdk-cpp/c++20-compilation-fixes.patch")
+    set(PATCH_FILE2 "${SOURCE_DIR}/thirdparty/aws-sdk-cpp/dll-export-injection.patch")
+    set(PATCH_FILE3 "${SOURCE_DIR}/thirdparty/aws-sdk-cpp/shutdown-fix.patch")
+    set(AWS_SDK_CPP_PATCH_COMMAND ${Bash_EXECUTABLE} -c "set -x &&\
+            (\"${Patch_EXECUTABLE}\" -p1 -R -s -f --dry-run -i \"${PATCH_FILE1}\" || \"${Patch_EXECUTABLE}\" -p1 -N -i \"${PATCH_FILE1}\") &&\
+            (\"${Patch_EXECUTABLE}\" -p1 -R -s -f --dry-run -i \"${PATCH_FILE2}\" || \"${Patch_EXECUTABLE}\" -p1 -N -i \"${PATCH_FILE2}\") &&\
+            (\"${Patch_EXECUTABLE}\" -p1 -R -s -f --dry-run -i \"${PATCH_FILE3}\" || \"${Patch_EXECUTABLE}\" -p1 -N -i \"${PATCH_FILE3}\") ")
 
     if (WIN32)
         set(CMAKE_INSTALL_LIBDIR "lib")
@@ -64,6 +69,10 @@ function(use_bundled_libaws SOURCE_DIR BINARY_DIR)
             -DBUILD_SHARED_LIBS=OFF
             -DENABLE_UNITY_BUILD=${AWS_ENABLE_UNITY_BUILD})
 
+    if(WIN32)
+        list(APPEND AWS_SDK_CPP_CMAKE_ARGS -DFORCE_EXPORT_CORE_API=ON -DFORCE_EXPORT_S3_API=ON)
+    endif()
+
     append_third_party_passthrough_args(AWS_SDK_CPP_CMAKE_ARGS "${AWS_SDK_CPP_CMAKE_ARGS}")
 
     ExternalProject_Add(
@@ -110,6 +119,9 @@ function(use_bundled_libaws SOURCE_DIR BINARY_DIR)
     add_dependencies(AWS::aws-c-io aws-sdk-cpp-external)
     target_include_directories(AWS::aws-c-io INTERFACE ${LIBAWS_INCLUDE_DIR})
     target_link_libraries(AWS::aws-c-io INTERFACE AWS::aws-c-common)
+    if (WIN32)
+        target_link_libraries(AWS::aws-c-io INTERFACE ncrypt.lib)
+    endif()
 
     add_library(AWS::aws-checksums STATIC IMPORTED)
     set_target_properties(AWS::aws-checksums PROPERTIES IMPORTED_LOCATION "${BINARY_DIR}/thirdparty/libaws-install/${CMAKE_INSTALL_LIBDIR}/${PREFIX}aws-checksums.${SUFFIX}")
diff --git a/cmake/BundledLibCoAP.cmake b/cmake/BundledLibCoAP.cmake
index 62a5705..8c47033 100644
--- a/cmake/BundledLibCoAP.cmake
+++ b/cmake/BundledLibCoAP.cmake
@@ -62,7 +62,7 @@ function(use_bundled_libcoap SOURCE_DIR BINARY_DIR)
                 INSTALL_COMMAND make install
                 BUILD_BYPRODUCTS "${BINARY_DIR}/thirdparty/libcoap-install/${BYPRODUCT}"
                 CONFIGURE_COMMAND ""
-                PATCH_COMMAND ./autogen.sh && ./configure "CFLAGS=${PASSTHROUGH_CMAKE_C_FLAGS} -fPIC" "CXXFLAGS=${PASSTHROUGH_CMAKE_CXX_FLAGS} -fPIC" --disable-examples --disable-dtls --disable-tests --disable-documentation --prefix=${BINARY_DIR}/thirdparty/libcoap-install
+                PATCH_COMMAND ./autogen.sh && ./configure "CFLAGS=${PASSTHROUGH_CMAKE_C_FLAGS} -fPIC" "CXXFLAGS=${PASSTHROUGH_CMAKE_CXX_FLAGS} -fPIC" --with-pic --disable-examples --disable-dtls --disable-tests --disable-documentation --prefix=${BINARY_DIR}/thirdparty/libcoap-install
                 STEP_TARGETS build
                 EXCLUDE_FROM_ALL TRUE
         )
diff --git a/cmake/BundledLibXml2.cmake b/cmake/BundledLibXml2.cmake
index 61ad939..9405196 100644
--- a/cmake/BundledLibXml2.cmake
+++ b/cmake/BundledLibXml2.cmake
@@ -67,7 +67,7 @@ function(use_bundled_libxml2 SOURCE_DIR BINARY_DIR)
                 INSTALL_COMMAND make install
                 BUILD_BYPRODUCTS "${BINARY_DIR}/thirdparty/libxml2-install/${BYPRODUCT}"
                 CONFIGURE_COMMAND ""
-                PATCH_COMMAND ./configure --enable-shared=no --enable-static=yes --with-iconv=no --with-zlib=no --with-lzma=no --with-python=no --with-ftp=no --with-http=no --prefix=${BINARY_DIR}/thirdparty/libxml2-install
+                PATCH_COMMAND ./configure --enable-shared=no --enable-static=yes --with-pic=yes --with-iconv=no --with-zlib=no --with-lzma=no --with-python=no --with-ftp=no --with-http=no --prefix=${BINARY_DIR}/thirdparty/libxml2-install
                 STEP_TARGETS build
                 EXCLUDE_FROM_ALL TRUE
         )
diff --git a/cmake/Extensions.cmake b/cmake/Extensions.cmake
index 144ffe5..a8b422c 100644
--- a/cmake/Extensions.cmake
+++ b/cmake/Extensions.cmake
@@ -26,7 +26,27 @@ macro(register_extension extension-name)
   get_property(extensions GLOBAL PROPERTY EXTENSION-OPTIONS)
   set_property(GLOBAL APPEND PROPERTY EXTENSION-OPTIONS ${extension-name})
   target_compile_definitions(${extension-name} PRIVATE "MODULE_NAME=${extension-name}")
-  set_target_properties(${extension-name} PROPERTIES ENABLE_EXPORTS True)
+  set_target_properties(${extension-name} PROPERTIES
+          ENABLE_EXPORTS True
+          POSITION_INDEPENDENT_CODE ON)
+  if (WIN32)
+    set_target_properties(${extension-name} PROPERTIES
+        RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
+        ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
+        WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
+  else()
+    set_target_properties(${extension-name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
+  endif()
+
+  if (WIN32)
+    install(TARGETS ${extension-name} RUNTIME DESTINATION extensions COMPONENT bin)
+  else()
+    if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+      target_link_options(${extension-name} PRIVATE "-Wl,--disable-new-dtags")
+    endif()
+    set_target_properties(${extension-name} PROPERTIES INSTALL_RPATH "$ORIGIN")
+    install(TARGETS ${extension-name} LIBRARY DESTINATION extensions COMPONENT bin)
+  endif()
 endmacro()
 
 ### TESTING MACROS
diff --git a/cmake/WholeArchive.cmake b/cmake/WholeArchive.cmake
index 44d7725..837bb05 100644
--- a/cmake/WholeArchive.cmake
+++ b/cmake/WholeArchive.cmake
@@ -33,3 +33,22 @@ function(target_wholearchive_library TARGET ITEM)
         add_dependencies(${TARGET} ${ITEM})
     endif()
 endfunction(target_wholearchive_library)
+
+function(target_wholearchive_library_private TARGET ITEM)
+    if (APPLE)
+        target_link_libraries(${TARGET} PRIVATE ${ITEM})
+        target_link_libraries(${TARGET} PRIVATE -Wl,-force_load,$<TARGET_FILE:${ITEM}>)
+        add_dependencies(${TARGET} ${ITEM})
+    elseif(WIN32)
+        target_link_libraries(${TARGET} PRIVATE ${ITEM})
+        if(${CMAKE_VERSION} VERSION_LESS "3.13.0")
+            set_property(TARGET ${TARGET} APPEND_STRING PROPERTY LINK_FLAGS " /WHOLEARCHIVE:$<TARGET_FILE:${ITEM}>")
+        else()
+            target_link_options(${TARGET} PRIVATE "/WHOLEARCHIVE:$<TARGET_FILE:${ITEM}>")
+        endif()
+        add_dependencies(${TARGET} ${ITEM})
+    else()
+        target_link_libraries(${TARGET} PRIVATE -Wl,--whole-archive ${ITEM} -Wl,--no-whole-archive)
+        add_dependencies(${TARGET} ${ITEM})
+    endif()
+endfunction(target_wholearchive_library_private)
diff --git a/conf/minifi.properties b/conf/minifi.properties
index 7720538..c2eb381 100644
--- a/conf/minifi.properties
+++ b/conf/minifi.properties
@@ -20,6 +20,9 @@ nifi.administrative.yield.duration=30 sec
 # If a component has no work to do (is "bored"), how long should we wait before checking again for work?
 nifi.bored.yield.duration=100 millis
 
+# Comma separated path for the extension libraries. Relative path is relative to the minifi executable.
+nifi.extension.path=../extensions/*
+
 # Provenance Repository #
 nifi.provenance.repository.directory.default=${MINIFI_HOME}/provenance_repository
 nifi.provenance.repository.max.storage.time=1 MIN
diff --git a/controller/CMakeLists.txt b/controller/CMakeLists.txt
index b41c1f6..215f819 100644
--- a/controller/CMakeLists.txt
+++ b/controller/CMakeLists.txt
@@ -31,20 +31,20 @@ include(CppVersion)
 set_cpp_version()
 
 add_executable(minificontroller MiNiFiController.cpp ../main/MainHelper.cpp)
-target_wholearchive_library(minificontroller minifi)
-target_link_libraries(minificontroller cxxopts Threads::Threads)
+target_link_libraries(minificontroller ${LIBMINIFI} cxxopts Threads::Threads)
 
-get_property(extensions GLOBAL PROPERTY EXTENSION-OPTIONS)
-foreach(EXTENSION ${extensions})
-	target_wholearchive_library(minificontroller ${EXTENSION})
-endforeach()
+set_target_properties(minificontroller PROPERTIES
+		OUTPUT_NAME minificontroller
+		RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
 
-set_target_properties(minificontroller PROPERTIES OUTPUT_NAME minificontroller)
+if (NOT WIN32)
+	if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+		target_link_options(minificontroller PRIVATE "-Wl,--disable-new-dtags")
+	endif()
+	set_target_properties(minificontroller PROPERTIES INSTALL_RPATH "$ORIGIN")
+endif()
 
-install(TARGETS minificontroller
-        RUNTIME
-        DESTINATION bin
-        COMPONENT bin)
+install(TARGETS minificontroller RUNTIME DESTINATION bin COMPONENT bin)
 
 add_custom_command(TARGET minificontroller POST_BUILD
            COMMAND cat ${CMAKE_BINARY_DIR}/all.log)
diff --git a/controller/Controller.h b/controller/Controller.h
index 99c475f..3bb5b85 100644
--- a/controller/Controller.h
+++ b/controller/Controller.h
@@ -326,7 +326,7 @@ void printManifest(const std::shared_ptr<minifi::Configure> &configuration) {
       prov_repo, flow_repo, content_repo, configuration, stream_factory, nifi_configuration_class_name);
 
   std::shared_ptr<minifi::FlowController> controller = std::unique_ptr<minifi::FlowController>(
-      new minifi::FlowController(prov_repo, flow_repo, configuration, std::move(flow_configuration), content_repo, "manifest", false));
+      new minifi::FlowController(prov_repo, flow_repo, configuration, std::move(flow_configuration), content_repo, "manifest"));
   controller->load();
   controller->start();
   std::this_thread::sleep_for(std::chrono::milliseconds(10000));
diff --git a/encrypt-config/CMakeLists.txt b/encrypt-config/CMakeLists.txt
index f818dd4..df4dd6e 100644
--- a/encrypt-config/CMakeLists.txt
+++ b/encrypt-config/CMakeLists.txt
@@ -19,7 +19,14 @@
 file(GLOB ENCRYPT_CONFIG_FILES  "*.cpp")
 add_executable(encrypt-config "${ENCRYPT_CONFIG_FILES}")
 target_include_directories(encrypt-config PRIVATE ../libminifi/include)
-target_wholearchive_library(encrypt-config minifi)
-target_link_libraries(encrypt-config libsodium)
+target_link_libraries(encrypt-config libsodium ${LIBMINIFI})
 set_target_properties(encrypt-config PROPERTIES OUTPUT_NAME encrypt-config)
+set_target_properties(encrypt-config PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
+
+if (NOT WIN32)
+  if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+    target_link_options(encrypt-config PRIVATE "-Wl,--disable-new-dtags")
+  endif()
+  set_target_properties(encrypt-config PROPERTIES INSTALL_RPATH "$ORIGIN")
+endif()
 install(TARGETS encrypt-config RUNTIME DESTINATION bin COMPONENT bin)
diff --git a/encrypt-config/tests/CMakeLists.txt b/encrypt-config/tests/CMakeLists.txt
index 5064c58..2379e91 100644
--- a/encrypt-config/tests/CMakeLists.txt
+++ b/encrypt-config/tests/CMakeLists.txt
@@ -31,8 +31,9 @@ foreach(testfile ${ENCRYPT_CONFIG_TESTS})
   target_include_directories(${testfilename} BEFORE PRIVATE "${CMAKE_SOURCE_DIR}/libminifi/include")
   target_include_directories(${testfilename} BEFORE PRIVATE "${CMAKE_SOURCE_DIR}/libminifi/test")
 
-  target_wholearchive_library(${testfilename} minifi)
-  target_link_libraries(${testfilename} ${CATCH_MAIN_LIB} ${TEST_BASE_LIB})
+  createTests(${testfilename})
+
+  target_link_libraries(${testfilename} ${CATCH_MAIN_LIB} ${LIBMINIFI} ${TEST_BASE_LIB})
   add_test(NAME ${testfilename} COMMAND ${testfilename} WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
 
   math(EXPR ENCRYPT_CONFIG_TEST_COUNT "${ENCRYPT_CONFIG_TEST_COUNT}+1")
diff --git a/extensions/aws/AWSLoader.h b/extensions/aws/AWSLoader.h
deleted file mode 100644
index 6419046..0000000
--- a/extensions/aws/AWSLoader.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <vector>
-#include <string>
-#include <memory>
-
-#include "core/ClassLoader.h"
-#include "utils/StringUtils.h"
-#include "controllerservices/AWSCredentialsService.h"
-#include "processors/PutS3Object.h"
-#include "processors/DeleteS3Object.h"
-#include "processors/FetchS3Object.h"
-#include "processors/ListS3.h"
-
-class AWSObjectFactory : public core::ObjectFactory {
- public:
-  AWSObjectFactory() = default;
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  std::string getName() override {
-    return "AWSObjectFactory";
-  }
-
-  std::string getClassName() override {
-    return "AWSObjectFactory";
-  }
-
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  std::vector<std::string> getClassNames() override {
-    std::vector<std::string> class_names;
-    class_names.push_back("AWSCredentialsService");
-    class_names.push_back("PutS3Object");
-    class_names.push_back("DeleteS3Object");
-    class_names.push_back("FetchS3Object");
-    class_names.push_back("ListS3");
-    return class_names;
-  }
-
-  std::unique_ptr<ObjectFactory> assign(const std::string &class_name) override {
-    if (utils::StringUtils::equalsIgnoreCase(class_name, "AWSCredentialsService")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::aws::controllers::AWSCredentialsService>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "PutS3Object")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::aws::processors::PutS3Object>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "DeleteS3Object")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::aws::processors::DeleteS3Object>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "FetchS3Object")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::aws::processors::FetchS3Object>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "ListS3")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::aws::processors::ListS3>());
-    } else {
-      return nullptr;
-    }
-  }
-
-  static bool added;
-};
-
-extern "C" {
-DLL_EXPORT void *createAWSFactory(void);
-}
diff --git a/extensions/aws/CMakeLists.txt b/extensions/aws/CMakeLists.txt
index 2a4bd63..d44b153 100644
--- a/extensions/aws/CMakeLists.txt
+++ b/extensions/aws/CMakeLists.txt
@@ -22,11 +22,16 @@ include_directories(controllerservices processors s3 ${CMAKE_SOURCE_DIR}/extensi
 
 file(GLOB SOURCES "*.cpp" "s3/*.cpp" "controllerservices/*.cpp" "processors/*.cpp" "utils/*.cpp")
 
-add_library(minifi-aws STATIC ${SOURCES})
+add_library(minifi-aws SHARED ${SOURCES})
 
-target_link_libraries(minifi-aws ${LIBMINIFI} Threads::Threads)
+target_link_libraries(minifi-aws PUBLIC ${LIBMINIFI} Threads::Threads)
 
-target_link_libraries(minifi-aws AWS::aws-cpp-sdk-s3)
+target_wholearchive_library_private(minifi-aws AWS::aws-cpp-sdk-s3)
+target_include_directories(minifi-aws INTERFACE $<TARGET_PROPERTY:AWS::aws-cpp-sdk-s3,INTERFACE_INCLUDE_DIRECTORIES>)
+if(WIN32)
+  target_compile_definitions(minifi-aws INTERFACE "AWS_CORE_API=__declspec(dllimport)")
+  target_compile_definitions(minifi-aws INTERFACE "AWS_S3_API=__declspec(dllimport)")
+endif()
 
 SET (AWS-EXTENSION minifi-aws PARENT_SCOPE)
 register_extension(minifi-aws)
diff --git a/extensions/aws/controllerservices/AWSCredentialsService.cpp b/extensions/aws/controllerservices/AWSCredentialsService.cpp
index 7b21012..b44e59c 100644
--- a/extensions/aws/controllerservices/AWSCredentialsService.cpp
+++ b/extensions/aws/controllerservices/AWSCredentialsService.cpp
@@ -20,6 +20,8 @@
 
 #include <set>
 
+#include "core/Resource.h"
+
 namespace org {
 namespace apache {
 namespace nifi {
@@ -83,6 +85,8 @@ std::optional<Aws::Auth::AWSCredentials> AWSCredentialsService::getAWSCredential
   return aws_credentials_;
 }
 
+REGISTER_RESOURCE(AWSCredentialsService, "AWS Credentials Management Service");
+
 }  // namespace controllers
 }  // namespace aws
 }  // namespace minifi
diff --git a/extensions/aws/controllerservices/AWSCredentialsService.h b/extensions/aws/controllerservices/AWSCredentialsService.h
index b3026d8..1599406 100644
--- a/extensions/aws/controllerservices/AWSCredentialsService.h
+++ b/extensions/aws/controllerservices/AWSCredentialsService.h
@@ -25,7 +25,6 @@
 #include "aws/core/auth/AWSCredentials.h"
 
 #include "utils/AWSInitializer.h"
-#include "core/Resource.h"
 #include "core/controller/ControllerService.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "AWSCredentialsProvider.h"
@@ -79,8 +78,6 @@ class AWSCredentialsService : public core::controller::ControllerService {
   AWSCredentialsProvider aws_credentials_provider_;
 };
 
-REGISTER_RESOURCE(AWSCredentialsService, "AWS Credentials Management Service");
-
 }  // namespace controllers
 }  // namespace aws
 }  // namespace minifi
diff --git a/extensions/aws/processors/DeleteS3Object.cpp b/extensions/aws/processors/DeleteS3Object.cpp
index 39601ae..2159e8a 100644
--- a/extensions/aws/processors/DeleteS3Object.cpp
+++ b/extensions/aws/processors/DeleteS3Object.cpp
@@ -23,6 +23,8 @@
 #include <set>
 #include <memory>
 
+#include "core/Resource.h"
+
 namespace org {
 namespace apache {
 namespace nifi {
@@ -100,6 +102,8 @@ void DeleteS3Object::onTrigger(const std::shared_ptr<core::ProcessContext> &cont
   }
 }
 
+REGISTER_RESOURCE(DeleteS3Object, "This Processor deletes FlowFiles on an Amazon S3 Bucket.");
+
 }  // namespace processors
 }  // namespace aws
 }  // namespace minifi
diff --git a/extensions/aws/processors/DeleteS3Object.h b/extensions/aws/processors/DeleteS3Object.h
index 52a6f19..5927d0c 100644
--- a/extensions/aws/processors/DeleteS3Object.h
+++ b/extensions/aws/processors/DeleteS3Object.h
@@ -77,8 +77,6 @@ class DeleteS3Object : public S3Processor {
     const CommonProperties &common_properties) const;
 };
 
-REGISTER_RESOURCE(DeleteS3Object, "This Processor deletes FlowFiles on an Amazon S3 Bucket.");
-
 }  // namespace processors
 }  // namespace aws
 }  // namespace minifi
diff --git a/extensions/aws/processors/FetchS3Object.cpp b/extensions/aws/processors/FetchS3Object.cpp
index b913f43..8bf25aa 100644
--- a/extensions/aws/processors/FetchS3Object.cpp
+++ b/extensions/aws/processors/FetchS3Object.cpp
@@ -23,6 +23,8 @@
 #include <set>
 #include <memory>
 
+#include "core/Resource.h"
+
 namespace org {
 namespace apache {
 namespace nifi {
@@ -134,6 +136,8 @@ void FetchS3Object::onTrigger(const std::shared_ptr<core::ProcessContext> &conte
   }
 }
 
+REGISTER_RESOURCE(FetchS3Object, "This Processor retrieves the contents of an S3 Object and writes it to the content of a FlowFile.");
+
 }  // namespace processors
 }  // namespace aws
 }  // namespace minifi
diff --git a/extensions/aws/processors/FetchS3Object.h b/extensions/aws/processors/FetchS3Object.h
index d248e73..366a89a 100644
--- a/extensions/aws/processors/FetchS3Object.h
+++ b/extensions/aws/processors/FetchS3Object.h
@@ -108,8 +108,6 @@ class FetchS3Object : public S3Processor {
   bool requester_pays_ = false;
 };
 
-REGISTER_RESOURCE(FetchS3Object, "This Processor retrieves the contents of an S3 Object and writes it to the content of a FlowFile.");
-
 }  // namespace processors
 }  // namespace aws
 }  // namespace minifi
diff --git a/extensions/aws/processors/ListS3.cpp b/extensions/aws/processors/ListS3.cpp
index ca6308f..2ec75de 100644
--- a/extensions/aws/processors/ListS3.cpp
+++ b/extensions/aws/processors/ListS3.cpp
@@ -27,6 +27,7 @@
 #include <memory>
 
 #include "utils/StringUtils.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -291,6 +292,8 @@ void ListS3::ListingState::updateState(const aws::s3::ListedObjectAttributes &ob
   }
 }
 
+REGISTER_RESOURCE(ListS3, "This Processor retrieves a listing of objects from an Amazon S3 bucket.");
+
 }  // namespace processors
 }  // namespace aws
 }  // namespace minifi
diff --git a/extensions/aws/processors/ListS3.h b/extensions/aws/processors/ListS3.h
index c302a39..8646ac2 100644
--- a/extensions/aws/processors/ListS3.h
+++ b/extensions/aws/processors/ListS3.h
@@ -105,8 +105,6 @@ class ListS3 : public S3Processor {
   std::shared_ptr<core::CoreComponentStateManager> state_manager_ = nullptr;
 };
 
-REGISTER_RESOURCE(ListS3, "This Processor retrieves a listing of objects from an Amazon S3 bucket.");
-
 }  // namespace processors
 }  // namespace aws
 }  // namespace minifi
diff --git a/extensions/aws/processors/PutS3Object.cpp b/extensions/aws/processors/PutS3Object.cpp
index bff91bf..093850b 100644
--- a/extensions/aws/processors/PutS3Object.cpp
+++ b/extensions/aws/processors/PutS3Object.cpp
@@ -29,6 +29,7 @@
 #include "properties/Properties.h"
 #include "utils/StringUtils.h"
 #include "utils/MapUtils.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -287,6 +288,8 @@ void PutS3Object::onTrigger(const std::shared_ptr<core::ProcessContext> &context
   }
 }
 
+REGISTER_RESOURCE(PutS3Object, "This Processor puts FlowFiles to an Amazon S3 Bucket.");
+
 }  // namespace processors
 }  // namespace aws
 }  // namespace minifi
diff --git a/extensions/aws/processors/PutS3Object.h b/extensions/aws/processors/PutS3Object.h
index 6623e73..09f3f1e 100644
--- a/extensions/aws/processors/PutS3Object.h
+++ b/extensions/aws/processors/PutS3Object.h
@@ -150,8 +150,6 @@ class PutS3Object : public S3Processor {
   std::string server_side_encryption_;
 };
 
-REGISTER_RESOURCE(PutS3Object, "This Processor puts FlowFiles to an Amazon S3 Bucket.");
-
 }  // namespace processors
 }  // namespace aws
 }  // namespace minifi
diff --git a/extensions/azure/AzureLoader.cpp b/extensions/azure/AzureLoader.cpp
deleted file mode 100644
index 2bde8c1..0000000
--- a/extensions/azure/AzureLoader.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "AzureLoader.h"
-#include "core/FlowConfiguration.h"
-
-bool AzureObjectFactory::added = core::FlowConfiguration::add_static_func("createAzureFactory");
-extern "C" {
-
-void *createAzureFactory(void) {
-  return new AzureObjectFactory();
-}
-
-}
diff --git a/extensions/azure/AzureLoader.h b/extensions/azure/AzureLoader.h
deleted file mode 100644
index 97de2e7..0000000
--- a/extensions/azure/AzureLoader.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <vector>
-#include <string>
-#include <memory>
-
-#include "core/ClassLoader.h"
-#include "utils/StringUtils.h"
-#include "controllerservices/AzureStorageCredentialsService.h"
-
-class AzureObjectFactory : public core::ObjectFactory {
- public:
-  AzureObjectFactory() = default;
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  std::string getName() override {
-    return "AzureObjectFactory";
-  }
-
-  std::string getClassName() override {
-    return "AzureObjectFactory";
-  }
-
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  std::vector<std::string> getClassNames() override {
-    std::vector<std::string> class_names;
-    class_names.push_back("AzureStorageCredentialsService");
-    return class_names;
-  }
-
-  std::unique_ptr<ObjectFactory> assign(const std::string &class_name) override {
-    if (utils::StringUtils::equalsIgnoreCase(class_name, "AzureStorageCredentialsService")) {
-      return std::make_unique<core::DefautObjectFactory<minifi::azure::controllers::AzureStorageCredentialsService>>();
-    } else {
-      return nullptr;
-    }
-  }
-
-  static bool added;
-};
-
-extern "C" {
-DLL_EXPORT void *createAzureFactory(void);
-}
diff --git a/extensions/azure/CMakeLists.txt b/extensions/azure/CMakeLists.txt
index 6478a3e..b8a8abc 100644
--- a/extensions/azure/CMakeLists.txt
+++ b/extensions/azure/CMakeLists.txt
@@ -21,7 +21,7 @@ include(${CMAKE_SOURCE_DIR}/extensions/ExtensionHeader.txt)
 
 file(GLOB SOURCES "*.cpp" "storage/*.cpp" "controllerservices/*.cpp" "processors/*.cpp")
 
-add_library(minifi-azure STATIC ${SOURCES})
+add_library(minifi-azure SHARED ${SOURCES})
 
 target_compile_features(minifi-azure PUBLIC cxx_std_14)
 
@@ -34,6 +34,10 @@ target_link_libraries(minifi-azure ${LIBMINIFI} Threads::Threads)
 target_link_libraries(minifi-azure CURL::libcurl LibXml2::LibXml2)
 target_link_libraries(minifi-azure AZURE::azure-storage-blobs AZURE::azure-storage-common AZURE::azure-core)
 
+if (WIN32)
+  target_link_libraries(minifi-azure crypt32.lib bcrypt.lib)
+endif()
+
 SET (AZURE-EXTENSION minifi-azure PARENT_SCOPE)
 register_extension(minifi-azure)
 
diff --git a/extensions/azure/controllerservices/AzureStorageCredentialsService.cpp b/extensions/azure/controllerservices/AzureStorageCredentialsService.cpp
index 7fea3c8..2796951 100644
--- a/extensions/azure/controllerservices/AzureStorageCredentialsService.cpp
+++ b/extensions/azure/controllerservices/AzureStorageCredentialsService.cpp
@@ -20,6 +20,8 @@
 
 #include <set>
 
+#include "core/Resource.h"
+
 namespace org {
 namespace apache {
 namespace nifi {
@@ -62,6 +64,8 @@ void AzureStorageCredentialsService::onEnable() {
   getProperty(ConnectionString.getName(), credentials_.connection_string);
 }
 
+REGISTER_RESOURCE(AzureStorageCredentialsService, "Azure Storage Credentials Management Service");
+
 }  // namespace controllers
 }  // namespace azure
 }  // namespace minifi
diff --git a/extensions/azure/controllerservices/AzureStorageCredentialsService.h b/extensions/azure/controllerservices/AzureStorageCredentialsService.h
index 84868e4..40aa843 100644
--- a/extensions/azure/controllerservices/AzureStorageCredentialsService.h
+++ b/extensions/azure/controllerservices/AzureStorageCredentialsService.h
@@ -21,7 +21,6 @@
 #include <string>
 #include <memory>
 
-#include "core/Resource.h"
 #include "core/controller/ControllerService.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "storage/AzureStorageCredentials.h"
@@ -75,8 +74,6 @@ class AzureStorageCredentialsService : public core::controller::ControllerServic
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(AzureStorageCredentialsService, "Azure Storage Credentials Management Service");
-
 }  // namespace controllers
 }  // namespace azure
 }  // namespace minifi
diff --git a/extensions/azure/processors/PutAzureBlobStorage.cpp b/extensions/azure/processors/PutAzureBlobStorage.cpp
index 9c53505..58ca495 100644
--- a/extensions/azure/processors/PutAzureBlobStorage.cpp
+++ b/extensions/azure/processors/PutAzureBlobStorage.cpp
@@ -25,6 +25,7 @@
 
 #include "storage/AzureBlobStorage.h"
 #include "controllerservices/AzureStorageCredentialsService.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -257,6 +258,8 @@ void PutAzureBlobStorage::onTrigger(const std::shared_ptr<core::ProcessContext>
   session->transfer(flow_file, Success);
 }
 
+REGISTER_RESOURCE(PutAzureBlobStorage, "Puts content into an Azure Storage Blob");
+
 }  // namespace processors
 }  // namespace azure
 }  // namespace minifi
diff --git a/extensions/azure/processors/PutAzureBlobStorage.h b/extensions/azure/processors/PutAzureBlobStorage.h
index 7c5330b..a712d0d 100644
--- a/extensions/azure/processors/PutAzureBlobStorage.h
+++ b/extensions/azure/processors/PutAzureBlobStorage.h
@@ -126,8 +126,6 @@ class PutAzureBlobStorage : public core::Processor {
   std::shared_ptr<logging::Logger> logger_{logging::LoggerFactory<PutAzureBlobStorage>::getLogger()};
 };
 
-REGISTER_RESOURCE(PutAzureBlobStorage, "Puts content into an Azure Storage Blob");
-
 }  // namespace processors
 }  // namespace azure
 }  // namespace minifi
diff --git a/extensions/bustache/ApplyTemplate.cpp b/extensions/bustache/ApplyTemplate.cpp
index 84b0338..8b6c2b3 100644
--- a/extensions/bustache/ApplyTemplate.cpp
+++ b/extensions/bustache/ApplyTemplate.cpp
@@ -29,6 +29,7 @@
 
 #include <bustache/model.hpp>
 
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -89,6 +90,9 @@ int64_t ApplyTemplate::WriteCallback::process(const std::shared_ptr<io::BaseStre
   return ostring.length();
 }
 
+REGISTER_RESOURCE(ApplyTemplate, "Applies the mustache template specified by the \"Template\" property and writes the output to the flow file content. "
+    "FlowFile attributes are used as template parameters.");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/bustache/ApplyTemplate.h b/extensions/bustache/ApplyTemplate.h
index a2c0e6f..f55264e 100644
--- a/extensions/bustache/ApplyTemplate.h
+++ b/extensions/bustache/ApplyTemplate.h
@@ -25,7 +25,6 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/FlowFile.h"
-#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -73,9 +72,6 @@ class ApplyTemplate : public core::Processor {
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(ApplyTemplate, "Applies the mustache template specified by the \"Template\" property and writes the output to the flow file content. "
-    "FlowFile attributes are used as template parameters.");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/bustache/CMakeLists.txt b/extensions/bustache/CMakeLists.txt
index 2dfb31d..42d9892 100644
--- a/extensions/bustache/CMakeLists.txt
+++ b/extensions/bustache/CMakeLists.txt
@@ -23,8 +23,7 @@ cmake_minimum_required(VERSION 2.6)
 
 file(GLOB SOURCES "*.cpp")
 
-add_library(minifi-bustache-extensions STATIC ${SOURCES})
-set_property(TARGET minifi-bustache-extensions PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-bustache-extensions SHARED ${SOURCES})
 
 target_link_libraries(minifi-bustache-extensions ${LIBMINIFI})
 target_link_libraries(minifi-bustache-extensions BUSTACHE::libbustache)
diff --git a/extensions/bustache/TemplateLoader.cpp b/extensions/bustache/TemplateLoader.cpp
deleted file mode 100644
index dd84a43..0000000
--- a/extensions/bustache/TemplateLoader.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "TemplateLoader.h"
-#include "core/FlowConfiguration.h"
-
-bool TemplateFactory::added = core::FlowConfiguration::add_static_func("createTemplateFactory");
-
-extern "C" {
-
-void *createTemplateFactory(void) {
-  return new TemplateFactory();
-}
-}
diff --git a/extensions/bustache/TemplateLoader.h b/extensions/bustache/TemplateLoader.h
deleted file mode 100644
index edc7808..0000000
--- a/extensions/bustache/TemplateLoader.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "ApplyTemplate.h"
-#include "core/ClassLoader.h"
-
-class TemplateFactory : public core::ObjectFactory {
- public:
-  TemplateFactory() = default;
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  virtual std::string getName() {
-    return "TemplateFactory";
-  }
-
-  virtual std::string getClassName() {
-    return "TemplateFactory";
-  }
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  virtual std::vector<std::string> getClassNames() {
-    std::vector<std::string> class_names;
-    class_names.push_back("ApplyTemplate");
-    return class_names;
-  }
-
-  virtual std::unique_ptr<ObjectFactory> assign(const std::string &class_name) {
-    if (utils::StringUtils::equalsIgnoreCase(class_name, "ApplyTemplate")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::processors::ApplyTemplate>());
-    } else {
-      return nullptr;
-    }
-  }
-
-  static bool added;
-};
-
-extern "C" {
-DLL_EXPORT void *createTemplateFactory(void);
-}
diff --git a/extensions/civetweb/CMakeLists.txt b/extensions/civetweb/CMakeLists.txt
index e7e8985..c5a2dca 100644
--- a/extensions/civetweb/CMakeLists.txt
+++ b/extensions/civetweb/CMakeLists.txt
@@ -26,8 +26,7 @@ include_directories(${CMAKE_SOURCE_DIR}/libminifi/include
 
 file(GLOB SOURCES  "processors/*.cpp")
 
-add_library(minifi-civet-extensions STATIC ${SOURCES})
-set_property(TARGET minifi-civet-extensions PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-civet-extensions SHARED ${SOURCES})
 target_link_libraries(minifi-civet-extensions ${LIBMINIFI} Threads::Threads)
 target_link_libraries(minifi-civet-extensions CIVETWEB::c-library CIVETWEB::civetweb-cpp)
 
diff --git a/extensions/civetweb/processors/ListenHTTP.cpp b/extensions/civetweb/processors/ListenHTTP.cpp
index 4ccff70..b5b6eeb 100644
--- a/extensions/civetweb/processors/ListenHTTP.cpp
+++ b/extensions/civetweb/processors/ListenHTTP.cpp
@@ -26,6 +26,7 @@
 #include <utility>
 #include <vector>
 
+#include "core/Resource.h"
 #include "utils/gsl.h"
 
 namespace org {
@@ -530,6 +531,13 @@ void ListenHTTP::notifyStop() {
   handler_.reset();
 }
 
+REGISTER_RESOURCE(ListenHTTP, "Starts an HTTP Server and listens on a given base path to transform incoming requests into FlowFiles. The default URI of the Service will be "
+    "http://{hostname}:{port}/contentListener. Only HEAD, POST, and GET requests are supported. PUT, and DELETE will result in an error and the HTTP response status code 405."
+    " The response body text for all requests, by default, is empty (length of 0). A static response body can be set for a given URI by sending input files to ListenHTTP with "
+    "the http.type attribute set to response_body. The response body FlowFile filename attribute is appended to the Base Path property (separated by a /) when mapped to incoming requests. "
+    "The mime.type attribute of the response body FlowFile is used for the Content-type header in responses. Response body content can be cleared by sending an empty (size 0) "
+    "FlowFile for a given URI mapping.");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/civetweb/processors/ListenHTTP.h b/extensions/civetweb/processors/ListenHTTP.h
index de522c3..8dda26b 100644
--- a/extensions/civetweb/processors/ListenHTTP.h
+++ b/extensions/civetweb/processors/ListenHTTP.h
@@ -31,10 +31,10 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Core.h"
-#include "core/Resource.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "utils/MinifiConcurrentQueue.h"
 #include "utils/gsl.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -61,20 +61,20 @@ class ListenHTTP : public core::Processor {
   // Destructor
   ~ListenHTTP() override;
   // Processor Name
-  static constexpr char const *ProcessorName = "ListenHTTP";
+  EXTENSIONAPI static constexpr char const *ProcessorName = "ListenHTTP";
   // Supported Properties
-  static core::Property BasePath;
-  static core::Property Port;
-  static core::Property AuthorizedDNPattern;
-  static core::Property SSLCertificate;
-  static core::Property SSLCertificateAuthority;
-  static core::Property SSLVerifyPeer;
-  static core::Property SSLMinimumVersion;
-  static core::Property HeadersAsAttributesRegex;
-  static core::Property BatchSize;
-  static core::Property BufferSize;
+  EXTENSIONAPI static core::Property BasePath;
+  EXTENSIONAPI static core::Property Port;
+  EXTENSIONAPI static core::Property AuthorizedDNPattern;
+  EXTENSIONAPI static core::Property SSLCertificate;
+  EXTENSIONAPI static core::Property SSLCertificateAuthority;
+  EXTENSIONAPI static core::Property SSLVerifyPeer;
+  EXTENSIONAPI static core::Property SSLMinimumVersion;
+  EXTENSIONAPI static core::Property HeadersAsAttributesRegex;
+  EXTENSIONAPI static core::Property BatchSize;
+  EXTENSIONAPI static core::Property BufferSize;
   // Supported Relationships
-  static core::Relationship Success;
+  EXTENSIONAPI static core::Relationship Success;
 
   void onTrigger(core::ProcessContext *context, core::ProcessSession *session) override;
   void initialize() override;
@@ -213,13 +213,6 @@ class ListenHTTP : public core::Processor {
   uint64_t batch_size_;
 };
 
-REGISTER_RESOURCE(ListenHTTP, "Starts an HTTP Server and listens on a given base path to transform incoming requests into FlowFiles. The default URI of the Service will be "
-    "http://{hostname}:{port}/contentListener. Only HEAD, POST, and GET requests are supported. PUT, and DELETE will result in an error and the HTTP response status code 405."
-    " The response body text for all requests, by default, is empty (length of 0). A static response body can be set for a given URI by sending input files to ListenHTTP with "
-    "the http.type attribute set to response_body. The response body FlowFile filename attribute is appended to the Base Path property (separated by a /) when mapped to incoming requests. "
-    "The mime.type attribute of the response body FlowFile is used for the Content-type header in responses. Response body content can be cleared by sending an empty (size 0) "
-    "FlowFile for a given URI mapping.");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/civetweb/tests/CMakeLists.txt b/extensions/civetweb/tests/CMakeLists.txt
index 10e056d..2766bcf 100644
--- a/extensions/civetweb/tests/CMakeLists.txt
+++ b/extensions/civetweb/tests/CMakeLists.txt
@@ -29,9 +29,9 @@ if(NOT DISABLE_CURL)
         target_include_directories(${testfilename} PRIVATE BEFORE "${CMAKE_SOURCE_DIR}/extensions/http-curl")
         target_include_directories(${testfilename} SYSTEM PRIVATE BEFORE "${CMAKE_SOURCE_DIR}/thirdparty/civetweb-1.10/include")
 
-        target_wholearchive_library(${testfilename} minifi-civet-extensions)
-        target_wholearchive_library(${testfilename} minifi-http-curl)
-        target_wholearchive_library(${testfilename} minifi-standard-processors)
+        target_link_libraries(${testfilename} minifi-civet-extensions)
+        target_link_libraries(${testfilename} minifi-http-curl)
+        target_link_libraries(${testfilename} minifi-standard-processors)
 
         createTests("${testfilename}")
         target_link_libraries(${testfilename} ${CATCH_MAIN_LIB})
diff --git a/extensions/coap/CMakeLists.txt b/extensions/coap/CMakeLists.txt
index f96f54c..c13c6a6 100644
--- a/extensions/coap/CMakeLists.txt
+++ b/extensions/coap/CMakeLists.txt
@@ -26,8 +26,7 @@ file(GLOB CSOURCES "nanofi/*.c")
 file(GLOB SOURCES "*.cpp" "protocols/*.cpp" "processors/*.cpp" "controllerservice/*.cpp" "server/*.cpp" )
 
 add_library(nanofi-coap-c STATIC ${CSOURCES})
-add_library(minifi-coap STATIC ${SOURCES})
-set_property(TARGET minifi-coap PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-coap SHARED ${SOURCES})
 
 target_link_libraries(nanofi-coap-c COAP::libcoap Threads::Threads)
 target_link_libraries(minifi-coap ${LIBMINIFI})
diff --git a/extensions/coap/COAPLoader.cpp b/extensions/coap/COAPLoader.cpp
index 6ed03c8..ae26bf5 100644
--- a/extensions/coap/COAPLoader.cpp
+++ b/extensions/coap/COAPLoader.cpp
@@ -15,17 +15,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include "core/FlowConfiguration.h"
+
 #include "core/logging/LoggerConfiguration.h"
-#include "COAPLoader.h"
+#include "core/extension/Extension.h"
 
 #ifdef WIN32
 #include <winsock2.h>
 #endif
 
-bool COAPObjectFactory::added = core::FlowConfiguration::add_static_func("createCOAPFactory");
-
-bool COAPObjectFactoryInitializer::initialize() {
+static bool init(const std::shared_ptr<org::apache::nifi::minifi::Configure> & /*config*/) {
 #ifdef WIN32
   static WSADATA s_wsaData;
   int iWinSockInitResult = WSAStartup(MAKEWORD(2, 2), &s_wsaData);
@@ -40,18 +38,10 @@ bool COAPObjectFactoryInitializer::initialize() {
 #endif
 }
 
-void COAPObjectFactoryInitializer::deinitialize() {
+static void deinit() {
 #ifdef WIN32
   WSACleanup();
 #endif
 }
 
-extern "C" {
-
-
-
-void *createCOAPFactory(void) {
-  return new COAPObjectFactory();
-}
-
-}
+REGISTER_EXTENSION("CoapExtension", init, deinit);
diff --git a/extensions/coap/COAPLoader.h b/extensions/coap/COAPLoader.h
deleted file mode 100644
index acbccd4..0000000
--- a/extensions/coap/COAPLoader.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#ifdef WIN32
-#pragma comment(lib, "wldap32.lib" )
-#pragma comment(lib, "crypt32.lib" )
-#pragma comment(lib, "Ws2_32.lib")
-#endif
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "core/ClassLoader.h"
-#include "utils/StringUtils.h"
-#include "protocols/CoapC2Protocol.h"
-
-class COAPObjectFactoryInitializer : public core::ObjectFactoryInitializer {
- public:
-  bool initialize() override;
-
-  void deinitialize() override;
-};
-
-/**
- * Object factory class loader for this extension.
- * Can add extensions to the default class loader through REGISTER_RESOURCE,
- * but we want to ensure this factory is used specifically for CoAP and not the default loader.
- */
-class COAPObjectFactory : public core::ObjectFactory {
- public:
-  COAPObjectFactory() = default;
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  std::string getName() override {
-    return "COAPObjectFactory";
-  }
-
-  std::string getClassName() override {
-    return "COAPObjectFactory";
-  }
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  std::vector<std::string> getClassNames() override {
-    std::vector<std::string> class_names;
-    class_names.push_back("CoapProtocol");
-    class_names.push_back("CoapConnectorService");
-    return class_names;
-  }
-
-  std::unique_ptr<ObjectFactory> assign(const std::string &class_name) override {
-    if (utils::StringUtils::equalsIgnoreCase(class_name, "CoapProtocol")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::coap::c2::CoapProtocol>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "CoapConnectorService")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::coap::controllers::CoapConnectorService>());
-    } else {
-      return nullptr;
-    }
-  }
-
-  std::unique_ptr<core::ObjectFactoryInitializer> getInitializer() override {
-    return std::unique_ptr<core::ObjectFactoryInitializer>(new COAPObjectFactoryInitializer());
-  }
-
-  static bool added;
-};
-
-extern "C" {
-  DLL_EXPORT void *createCOAPFactory(void);
-}
diff --git a/extensions/coap/controllerservice/CoapConnector.cpp b/extensions/coap/controllerservice/CoapConnector.cpp
index d90be2a..881797d 100644
--- a/extensions/coap/controllerservice/CoapConnector.cpp
+++ b/extensions/coap/controllerservice/CoapConnector.cpp
@@ -25,6 +25,7 @@
 #include "core/logging/LoggerConfiguration.h"
 #include "core/controller/ControllerService.h"
 #include "core/Property.h"
+#include "core/Resource.h"
 #include "io/validation.h"
 #include "properties/Configure.h"
 
@@ -90,6 +91,8 @@ void CoapConnectorService::initializeProperties() {
   setSupportedProperties(supportedProperties);
 }
 
+REGISTER_INTERNAL_RESOURCE(CoapConnectorService);
+
 } /* namespace controllers */
 } /* namespace coap */
 } /* namespace minifi */
diff --git a/extensions/coap/controllerservice/CoapConnector.h b/extensions/coap/controllerservice/CoapConnector.h
index 1524ab0..f8fa7dd 100644
--- a/extensions/coap/controllerservice/CoapConnector.h
+++ b/extensions/coap/controllerservice/CoapConnector.h
@@ -107,6 +107,7 @@ class CoapConnectorService : public core::controller::ControllerService {
 
   std::shared_ptr<logging::Logger> logger_{ logging::LoggerFactory<CoapConnectorService>::getLogger() };
 };
+
 } /* namespace controllers */
 } /* namespace coap */
 } /* namespace minifi */
diff --git a/extensions/coap/protocols/CoapC2Protocol.cpp b/extensions/coap/protocols/CoapC2Protocol.cpp
index d3343e0..fb94510 100644
--- a/extensions/coap/protocols/CoapC2Protocol.cpp
+++ b/extensions/coap/protocols/CoapC2Protocol.cpp
@@ -21,6 +21,7 @@
 #include "coap_functions.h"
 #include "coap_message.h"
 #include "io/BaseStream.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -290,6 +291,8 @@ minifi::c2::C2Payload CoapProtocol::serialize(const minifi::c2::C2Payload &paylo
   return minifi::c2::C2Payload(payload.getOperation(), state::UpdateState::READ_ERROR);
 }
 
+REGISTER_INTERNAL_RESOURCE(CoapProtocol);
+
 } /* namespace c2 */
 } /* namespace coap */
 } /* namespace minifi */
diff --git a/extensions/coap/protocols/CoapC2Protocol.h b/extensions/coap/protocols/CoapC2Protocol.h
index c7852a2..e23280e 100644
--- a/extensions/coap/protocols/CoapC2Protocol.h
+++ b/extensions/coap/protocols/CoapC2Protocol.h
@@ -131,6 +131,7 @@ class CoapProtocol : public minifi::c2::RESTSender {
 
   std::shared_ptr<logging::Logger> logger_;
 };
+
 } /* namespace c2 */
 } /* namespace coap */
 } /* namespace minifi */
diff --git a/extensions/coap/tests/CMakeLists.txt b/extensions/coap/tests/CMakeLists.txt
index df4b266..8ef0d88 100644
--- a/extensions/coap/tests/CMakeLists.txt
+++ b/extensions/coap/tests/CMakeLists.txt
@@ -40,10 +40,10 @@ FOREACH(testfile ${COAP_INTEGRATION_TESTS})
 	target_include_directories(${testfilename} BEFORE PRIVATE "${CMAKE_SOURCE_DIR}/extensions/civetweb/")
 	target_include_directories(${testfilename} BEFORE PRIVATE ./include)
 	createTests("${testfilename}")
-	target_wholearchive_library(${testfilename} minifi-coap)
-	target_wholearchive_library(${testfilename} minifi-civet-extensions)
-	target_wholearchive_library(${testfilename} minifi-http-curl)
-	target_wholearchive_library(${testfilename} minifi-standard-processors)
+	target_link_libraries(${testfilename} minifi-coap)
+	target_link_libraries(${testfilename} minifi-civet-extensions)
+	target_link_libraries(${testfilename} minifi-http-curl)
+	target_link_libraries(${testfilename} minifi-standard-processors)
 
     MATH(EXPR CURL_INT_TEST_COUNT "${CURL_INT_TEST_COUNT}+1")
 ENDFOREACH()
diff --git a/extensions/coap/tests/CoapIntegrationBase.h b/extensions/coap/tests/CoapIntegrationBase.h
index e247954..de5aedb 100644
--- a/extensions/coap/tests/CoapIntegrationBase.h
+++ b/extensions/coap/tests/CoapIntegrationBase.h
@@ -72,8 +72,7 @@ class CoapIntegrationBase : public IntegrationBase {
 
     std::shared_ptr<TestRepository> repo = std::static_pointer_cast<TestRepository>(test_repo);
 
-    std::shared_ptr<minifi::FlowController> controller = std::make_shared<minifi::FlowController>(test_repo, test_flow_repo, configuration, std::move(yaml_ptr), content_repo, DEFAULT_ROOT_GROUP_NAME,
-                                                                                                  true);
+    std::shared_ptr<minifi::FlowController> controller = std::make_shared<minifi::FlowController>(test_repo, test_flow_repo, configuration, std::move(yaml_ptr), content_repo, DEFAULT_ROOT_GROUP_NAME);
 
     controller->load();
     controller->start();
diff --git a/extensions/expression-language/CMakeLists.txt b/extensions/expression-language/CMakeLists.txt
index f1071be..42a7e8a 100644
--- a/extensions/expression-language/CMakeLists.txt
+++ b/extensions/expression-language/CMakeLists.txt
@@ -96,8 +96,7 @@ if (NOT WIN32)
 	set_source_files_properties(${FLEX_el-scanner_OUTPUTS} PROPERTIES COMPILE_FLAGS -Wno-error)
 endif()
 
-add_library(minifi-expression-language-extensions STATIC ${SOURCES} ${BISON_el-parser_OUTPUTS} ${FLEX_el-scanner_OUTPUTS})
-set_property(TARGET minifi-expression-language-extensions PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-expression-language-extensions SHARED ${SOURCES} ${BISON_el-parser_OUTPUTS} ${FLEX_el-scanner_OUTPUTS})
 
 target_link_libraries(minifi-expression-language-extensions ${LIBMINIFI})
 target_link_libraries(minifi-expression-language-extensions date::tz RapidJSON CURL::libcurl)
diff --git a/extensions/expression-language/ExpressionContextBuilder.cpp b/extensions/expression-language/ExpressionContextBuilder.cpp
index d546f1e..5a568e7 100644
--- a/extensions/expression-language/ExpressionContextBuilder.cpp
+++ b/extensions/expression-language/ExpressionContextBuilder.cpp
@@ -21,6 +21,7 @@
 #include <string>
 
 #include "ProcessContextExpr.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -43,6 +44,8 @@ std::shared_ptr<core::ProcessContext> ExpressionContextBuilder::build(const std:
   return std::make_shared<core::ProcessContextExpr>(processor, controller_service_provider_, prov_repo_, flow_repo_, configuration_, content_repo_);
 }
 
+REGISTER_INTERNAL_RESOURCE_AS(ExpressionContextBuilder, ("ProcessContextBuilder"));
+
 } /* namespace expressions */
 } /* namespace core */
 } /* namespace minifi */
diff --git a/extensions/expression-language/ExpressionLoader.cpp b/extensions/expression-language/ExpressionLoader.cpp
deleted file mode 100644
index 155bfd8..0000000
--- a/extensions/expression-language/ExpressionLoader.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "core/FlowConfiguration.h"
-#include "ExpressionLoader.h"
-
-bool ExpressionObjectFactory::added = core::FlowConfiguration::add_static_func("createExpressionFactory");
-extern "C" {
-void *createExpressionFactory(void) {
-  return new ExpressionObjectFactory();
-}
-
-}
diff --git a/extensions/expression-language/ExpressionLoader.h b/extensions/expression-language/ExpressionLoader.h
deleted file mode 100644
index e593e03..0000000
--- a/extensions/expression-language/ExpressionLoader.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-#include <vector>
-#include <string>
-#include <memory>
-
-#include "core/ClassLoader.h"
-#include "utils/StringUtils.h"
-#include "ExpressionContextBuilder.h"
-
-/**
- * Object factory class loader for this extension.
- * Can add extensions to the default class loader through REGISTER_RESOURCE,
- * but we want to ensure this factory is used specifically for CoAP and not the default loader.
- */
-class ExpressionObjectFactory : public core::ObjectFactory {
- public:
-  ExpressionObjectFactory() = default;
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  std::string getName() override {
-    return "ExpressionObjectFactory";
-  }
-
-  std::string getClassName() override {
-    return "ExpressionObjectFactory";
-  }
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  std::vector<std::string> getClassNames() override {
-    std::vector<std::string> class_names;
-    class_names.push_back("ProcessContextBuilder");
-    return class_names;
-  }
-
-  std::unique_ptr<ObjectFactory> assign(const std::string &class_name) override {
-    if (utils::StringUtils::equalsIgnoreCase(class_name, "ProcessContextBuilder")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<core::expressions::ExpressionContextBuilder>());
-    } else {
-      return nullptr;
-    }
-  }
-
-  static bool added;
-};
-
-extern "C" {
-DLL_EXPORT void *createExpressionFactory(void);
-}
diff --git a/extensions/expression-language/tests/CMakeLists.txt b/extensions/expression-language/tests/CMakeLists.txt
index fdb9699..d2d2d8d 100644
--- a/extensions/expression-language/tests/CMakeLists.txt
+++ b/extensions/expression-language/tests/CMakeLists.txt
@@ -36,8 +36,8 @@ if(NOT WIN32)
 		if(NOT DISABLE_CURL)
 			target_link_libraries(${testfilename} CURL::libcurl)
 		endif()
-		target_wholearchive_library(${testfilename} minifi-expression-language-extensions)
-		target_wholearchive_library(${testfilename} minifi-standard-processors)
+		target_link_libraries(${testfilename} minifi-expression-language-extensions)
+		target_link_libraries(${testfilename} minifi-standard-processors)
 
 		MATH(EXPR EXTENSIONS_TEST_COUNT "${EXTENSIONS_TEST_COUNT}+1")
 		add_test(NAME ${testfilename} COMMAND ${testfilename} WORKING_DIRECTORY ${TEST_DIR})
@@ -64,8 +64,8 @@ FOREACH(testfile ${INT_EXPRESSION_LANGUAGE_TESTS})
 	if(NOT DISABLE_CURL)
 		target_link_libraries(${testfilename} CURL::libcurl)
 	endif()
-	target_wholearchive_library(${testfilename} minifi-expression-language-extensions)
-	target_wholearchive_library(${testfilename} minifi-standard-processors)
+	target_link_libraries(${testfilename} minifi-expression-language-extensions)
+	target_link_libraries(${testfilename} minifi-standard-processors)
 
 	MATH(EXPR EXTENSIONS_TEST_COUNT "${INT_EXTENSIONS_TEST_COUNT}+1")
 ENDFOREACH()
diff --git a/extensions/gps/CMakeLists.txt b/extensions/gps/CMakeLists.txt
index cb43c9e..6eb0704 100644
--- a/extensions/gps/CMakeLists.txt
+++ b/extensions/gps/CMakeLists.txt
@@ -25,9 +25,7 @@ include_directories(${LIBGPS_INCLUDE_DIRS})
 
 file(GLOB SOURCES  "*.cpp")
 
-add_library(minifi-gps STATIC ${SOURCES})
-set_property(TARGET minifi-gps PROPERTY POSITION_INDEPENDENT_CODE ON)
-
+add_library(minifi-gps SHARED ${SOURCES})
 
 # Include UUID
 target_link_libraries(minifi-gps ${LIBMINIFI} )
diff --git a/extensions/gps/GetGPS.cpp b/extensions/gps/GetGPS.cpp
index 3f516f5..a8af0bd 100644
--- a/extensions/gps/GetGPS.cpp
+++ b/extensions/gps/GetGPS.cpp
@@ -34,6 +34,7 @@
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
 #include "core/PropertyValidation.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -149,6 +150,8 @@ void GetGPS::onTrigger(const std::shared_ptr<core::ProcessContext>& /*context*/,
   }
 }
 
+REGISTER_RESOURCE(GetGPS, "Obtains GPS coordinates from the GPSDHost and port.");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/gps/GetGPS.h b/extensions/gps/GetGPS.h
index 6ba80a8..815fd2b 100644
--- a/extensions/gps/GetGPS.h
+++ b/extensions/gps/GetGPS.h
@@ -70,9 +70,6 @@ class GetGPS : public core::Processor {
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(GetGPS, "Obtains GPS coordinates from the GPSDHost and port.");
-
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/gps/GetGPSLoader.h b/extensions/gps/GetGPSLoader.h
deleted file mode 100644
index d0e74f4..0000000
--- a/extensions/gps/GetGPSLoader.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include "GetGPS.h"
-
-#include <vector>
-#include <memory>
-#include <string>
-
-#include "core/ClassLoader.h"
-#include "utils/StringUtils.h"
-
-class GpsFactory : public core::ObjectFactory {
- public:
-  GpsFactory() = default;
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  virtual std::string getName() {
-    return "GpsFactory";
-  }
-
-  virtual std::string getClassName() {
-    return "GpsFactory";
-  }
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  virtual std::vector<std::string> getClassNames() {
-    std::vector<std::string> class_names;
-    class_names.push_back("GetGPS");
-    return class_names;
-  }
-
-  virtual std::unique_ptr<ObjectFactory> assign(const std::string &class_name) {
-    if (minifi::utils::StringUtils::equalsIgnoreCase(class_name, "GetGPS")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::processors::GetGPS>());
-    } else {
-      return nullptr;
-    }
-  }
-
-  static bool added;
-};
-
-extern "C" {
-DLL_EXPORT void *createGPSFactory(void);
-}
diff --git a/extensions/gps/GetGpsLoader.cpp b/extensions/gps/GetGpsLoader.cpp
deleted file mode 100644
index 2adb2de..0000000
--- a/extensions/gps/GetGpsLoader.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "core/FlowConfiguration.h"
-#include "GetGPSLoader.h"
-
-bool GpsFactory::added = core::FlowConfiguration::add_static_func("createGPSFactory");
-
-extern "C" {
-
-void *createGPSFactory(void) {
-  return new GpsFactory();
-}
-
-}
diff --git a/extensions/http-curl/CMakeLists.txt b/extensions/http-curl/CMakeLists.txt
index 0df998c..ec1cf83 100644
--- a/extensions/http-curl/CMakeLists.txt
+++ b/extensions/http-curl/CMakeLists.txt
@@ -22,8 +22,7 @@ include_directories(protocols client processors sitetosite)
 
 file(GLOB SOURCES  "*.cpp" "protocols/*.cpp" "client/*.cpp" "processors/*.cpp" "sitetosite/*.cpp")
 
-add_library(minifi-http-curl STATIC ${SOURCES})
-set_property(TARGET minifi-http-curl PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-http-curl SHARED ${SOURCES})
 
 target_link_libraries(minifi-http-curl ${LIBMINIFI} Threads::Threads)
 target_link_libraries(minifi-http-curl CURL::libcurl RapidJSON)
diff --git a/extensions/http-curl/HTTPCurlLoader.cpp b/extensions/http-curl/HTTPCurlLoader.cpp
index d898ffc..449fa16 100644
--- a/extensions/http-curl/HTTPCurlLoader.cpp
+++ b/extensions/http-curl/HTTPCurlLoader.cpp
@@ -1,5 +1,4 @@
 /**
- *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
@@ -15,13 +14,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include "HTTPCurlLoader.h"
 
-#include "core/FlowConfiguration.h"
+#ifdef WIN32
+#pragma comment(lib, "wldap32.lib" )
+#pragma comment(lib, "crypt32.lib" )
+#pragma comment(lib, "Ws2_32.lib")
+
+#define CURL_STATICLIB
+#include <curl/curl.h>
+#endif
+
+#include "core/extension/Extension.h"
 
-bool HttpCurlObjectFactory::added = core::FlowConfiguration::add_static_func("createHttpCurlFactory");
-extern "C" {
-void *createHttpCurlFactory(void) {
-  return new HttpCurlObjectFactory();
+#include "client/HTTPClient.h"
+
+static bool init(const core::extension::ExtensionConfig& /*config*/) {
+  return curl_global_init(CURL_GLOBAL_DEFAULT) == CURLE_OK;
 }
+
+static void deinit() {
+  curl_global_cleanup();
 }
+
+REGISTER_EXTENSION("HttpCurlExtension", init, deinit);
diff --git a/extensions/http-curl/HTTPCurlLoader.h b/extensions/http-curl/HTTPCurlLoader.h
deleted file mode 100644
index 521d3e2..0000000
--- a/extensions/http-curl/HTTPCurlLoader.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#ifdef WIN32
-#pragma comment(lib, "wldap32.lib" )
-#pragma comment(lib, "crypt32.lib" )
-#pragma comment(lib, "Ws2_32.lib")
-
-#define CURL_STATICLIB
-#include <curl/curl.h>
-#endif
-
-#include <vector>
-#include <string>
-#include <memory>
-
-#include "c2/protocols/RESTProtocol.h"
-#include "protocols/RESTSender.h"
-#include "processors/InvokeHTTP.h"
-#include "client/HTTPClient.h"
-#include "core/ClassLoader.h"
-#include "sitetosite/HTTPProtocol.h"
-#include "utils/StringUtils.h"
-
-class HttpCurlObjectFactoryInitializer : public core::ObjectFactoryInitializer {
- public:
-  virtual bool initialize() {
-    return curl_global_init(CURL_GLOBAL_DEFAULT) == CURLE_OK;
-  }
-
-  virtual void deinitialize() {
-    curl_global_cleanup();
-  }
-};
-
-class HttpCurlObjectFactory : public core::ObjectFactory {
- public:
-  HttpCurlObjectFactory() = default;
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  std::string getName() override {
-    return "HttpCurlObjectFactory";
-  }
-
-  std::string getClassName() override {
-    return "HttpCurlObjectFactory";
-  }
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  std::vector<std::string> getClassNames() override {
-    std::vector<std::string> class_names;
-    class_names.push_back("HttpProtocol");
-    class_names.push_back("RESTSender");
-    class_names.push_back("InvokeHTTP");
-    class_names.push_back("HTTPClient");
-    class_names.push_back("HttpSiteToSiteClient");
-    return class_names;
-  }
-
-  std::unique_ptr<ObjectFactory> assign(const std::string &class_name) override {
-    if (utils::StringUtils::equalsIgnoreCase(class_name, "RESTSender")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::c2::RESTSender>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "InvokeHTTP")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<processors::InvokeHTTP>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "HTTPClient")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<utils::HTTPClient>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "HttpProtocol") || utils::StringUtils::equalsIgnoreCase(class_name, "HttpSiteToSiteClient")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::sitetosite::HttpSiteToSiteClient>());
-    } else {
-      return nullptr;
-    }
-  }
-
-  std::unique_ptr<core::ObjectFactoryInitializer> getInitializer() override {
-    return std::unique_ptr<core::ObjectFactoryInitializer>(new HttpCurlObjectFactoryInitializer());
-  }
-
-  static bool added;
-};
-
-extern "C" {
-  DLL_EXPORT void *createHttpCurlFactory(void);
-}
diff --git a/extensions/http-curl/client/HTTPClient.cpp b/extensions/http-curl/client/HTTPClient.cpp
index d4d28dc..9d4e26c 100644
--- a/extensions/http-curl/client/HTTPClient.cpp
+++ b/extensions/http-curl/client/HTTPClient.cpp
@@ -28,6 +28,7 @@
 #include "Exception.h"
 #include "utils/gsl.h"
 #include "utils/StringUtils.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -430,6 +431,8 @@ void HTTPClient::setFollowRedirects(bool follow) {
   curl_easy_setopt(http_session_, CURLOPT_FOLLOWLOCATION, follow);
 }
 
+REGISTER_INTERNAL_RESOURCE(HTTPClient);
+
 }  // namespace utils
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/http-curl/processors/InvokeHTTP.cpp b/extensions/http-curl/processors/InvokeHTTP.cpp
index 34b4db1..564e0ee 100644
--- a/extensions/http-curl/processors/InvokeHTTP.cpp
+++ b/extensions/http-curl/processors/InvokeHTTP.cpp
@@ -33,6 +33,7 @@
 #include "core/FlowFile.h"
 #include "core/ProcessContext.h"
 #include "core/Relationship.h"
+#include "core/Resource.h"
 #include "io/BufferStream.h"
 #include "io/StreamFactory.h"
 #include "ResourceClaim.h"
@@ -450,6 +451,10 @@ void InvokeHTTP::route(const std::shared_ptr<core::FlowFile> &request, const std
   }
 }
 
+REGISTER_RESOURCE(InvokeHTTP, "An HTTP client processor which can interact with a configurable HTTP Endpoint. "
+    "The destination URL and HTTP Method are configurable. FlowFile attributes are converted to HTTP headers and the "
+    "FlowFile contents are included as the body of the request (if the HTTP Method is PUT, POST or PATCH).");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/http-curl/processors/InvokeHTTP.h b/extensions/http-curl/processors/InvokeHTTP.h
index 766729f..789f5c0 100644
--- a/extensions/http-curl/processors/InvokeHTTP.h
+++ b/extensions/http-curl/processors/InvokeHTTP.h
@@ -26,11 +26,11 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Property.h"
-#include "core/Resource.h"
 #include "controllers/SSLContextService.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "utils/Id.h"
 #include "../client/HTTPClient.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -52,46 +52,46 @@ class InvokeHTTP : public core::Processor {
   // Destructor
   virtual ~InvokeHTTP();
   // Processor Name
-  static const char *ProcessorName;
-  static std::string DefaultContentType;
+  EXTENSIONAPI static const char *ProcessorName;
+  EXTENSIONAPI static std::string DefaultContentType;
   // Supported Properties
-  static core::Property Method;
-  static core::Property URL;
-  static core::Property ConnectTimeout;
-  static core::Property ReadTimeout;
-  static core::Property DateHeader;
-  static core::Property FollowRedirects;
-  static core::Property AttributesToSend;
-  static core::Property SSLContext;
-  static core::Property ProxyHost;
-  static core::Property ProxyPort;
-  static core::Property ProxyUsername;
-  static core::Property ProxyPassword;
-  static core::Property ContentType;
-  static core::Property SendBody;
-  static core::Property SendMessageBody;
-  static core::Property UseChunkedEncoding;
-  static core::Property DisablePeerVerification;
-  static core::Property PropPutOutputAttributes;
+  EXTENSIONAPI static core::Property Method;
+  EXTENSIONAPI static core::Property URL;
+  EXTENSIONAPI static core::Property ConnectTimeout;
+  EXTENSIONAPI static core::Property ReadTimeout;
+  EXTENSIONAPI static core::Property DateHeader;
+  EXTENSIONAPI static core::Property FollowRedirects;
+  EXTENSIONAPI static core::Property AttributesToSend;
+  EXTENSIONAPI static core::Property SSLContext;
+  EXTENSIONAPI static core::Property ProxyHost;
+  EXTENSIONAPI static core::Property ProxyPort;
+  EXTENSIONAPI static core::Property ProxyUsername;
+  EXTENSIONAPI static core::Property ProxyPassword;
+  EXTENSIONAPI static core::Property ContentType;
+  EXTENSIONAPI static core::Property SendBody;
+  EXTENSIONAPI static core::Property SendMessageBody;
+  EXTENSIONAPI static core::Property UseChunkedEncoding;
+  EXTENSIONAPI static core::Property DisablePeerVerification;
+  EXTENSIONAPI static core::Property PropPutOutputAttributes;
 
-  static core::Property AlwaysOutputResponse;
+  EXTENSIONAPI static core::Property AlwaysOutputResponse;
 
-  static core::Property PenalizeOnNoRetry;
+  EXTENSIONAPI static core::Property PenalizeOnNoRetry;
 
-  static const char* STATUS_CODE;
-  static const char* STATUS_MESSAGE;
-  static const char* RESPONSE_BODY;
-  static const char* REQUEST_URL;
-  static const char* TRANSACTION_ID;
-  static const char* REMOTE_DN;
-  static const char* EXCEPTION_CLASS;
-  static const char* EXCEPTION_MESSAGE;
+  EXTENSIONAPI static const char* STATUS_CODE;
+  EXTENSIONAPI static const char* STATUS_MESSAGE;
+  EXTENSIONAPI static const char* RESPONSE_BODY;
+  EXTENSIONAPI static const char* REQUEST_URL;
+  EXTENSIONAPI static const char* TRANSACTION_ID;
+  EXTENSIONAPI static const char* REMOTE_DN;
+  EXTENSIONAPI static const char* EXCEPTION_CLASS;
+  EXTENSIONAPI static const char* EXCEPTION_MESSAGE;
   // Supported Relationships
-  static core::Relationship Success;
-  static core::Relationship RelResponse;
-  static core::Relationship RelRetry;
-  static core::Relationship RelNoRetry;
-  static core::Relationship RelFailure;
+  EXTENSIONAPI static core::Relationship Success;
+  EXTENSIONAPI static core::Relationship RelResponse;
+  EXTENSIONAPI static core::Relationship RelRetry;
+  EXTENSIONAPI static core::Relationship RelNoRetry;
+  EXTENSIONAPI static core::Relationship RelFailure;
 
   void onTrigger(const std::shared_ptr<core::ProcessContext> &context, const std::shared_ptr<core::ProcessSession> &session) override;
   void initialize() override;
@@ -162,10 +162,6 @@ class InvokeHTTP : public core::Processor {
   std::shared_ptr<logging::Logger> logger_{logging::LoggerFactory<InvokeHTTP>::getLogger()};
 };
 
-REGISTER_RESOURCE(InvokeHTTP, "An HTTP client processor which can interact with a configurable HTTP Endpoint. "
-    "The destination URL and HTTP Method are configurable. FlowFile attributes are converted to HTTP headers and the "
-    "FlowFile contents are included as the body of the request (if the HTTP Method is PUT, POST or PATCH).");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/http-curl/protocols/AgentPrinter.cpp b/extensions/http-curl/protocols/AgentPrinter.cpp
index 2d9c7c7..1183f11 100644
--- a/extensions/http-curl/protocols/AgentPrinter.cpp
+++ b/extensions/http-curl/protocols/AgentPrinter.cpp
@@ -23,6 +23,7 @@
 #include <string>
 
 #include "rapidjson/prettywriter.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -60,6 +61,8 @@ rapidjson::Value AgentPrinter::serializeJsonPayload(const C2Payload &payload, ra
   return result;
 }
 
+REGISTER_RESOURCE(AgentPrinter, "Encapsulates printing agent information.");
+
 } /* namespace c2 */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/http-curl/protocols/AgentPrinter.h b/extensions/http-curl/protocols/AgentPrinter.h
index f471ec0..2054a0a 100644
--- a/extensions/http-curl/protocols/AgentPrinter.h
+++ b/extensions/http-curl/protocols/AgentPrinter.h
@@ -19,7 +19,6 @@
 
 #include <string>
 #include <memory>
-#include "core/Resource.h"
 #include "c2/protocols/RESTProtocol.h"
 #include "c2/C2Protocol.h"
 
@@ -59,8 +58,6 @@ class AgentPrinter : public HeartbeatJsonSerializer, public HeartbeatReporter {
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(AgentPrinter, "Encapsulates printing agent information.");
-
 } /* namespace c2 */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/http-curl/protocols/RESTReceiver.cpp b/extensions/http-curl/protocols/RESTReceiver.cpp
index 224ffc3..e693a32 100644
--- a/extensions/http-curl/protocols/RESTReceiver.cpp
+++ b/extensions/http-curl/protocols/RESTReceiver.cpp
@@ -17,6 +17,7 @@
  */
 
 #include "RESTReceiver.h"
+
 #include <algorithm>
 #include <memory>
 #include <utility>
@@ -24,6 +25,8 @@
 #include <string>
 #include <vector>
 
+#include "core/Resource.h"
+
 namespace org {
 namespace apache {
 namespace nifi {
@@ -108,6 +111,8 @@ std::unique_ptr<CivetServer> RESTReceiver::start_webserver(const std::string &po
   return server;
 }
 
+REGISTER_RESOURCE(RESTReceiver, "Provides a webserver to display C2 heartbeat information");
+
 } /* namespace c2 */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/http-curl/protocols/RESTReceiver.h b/extensions/http-curl/protocols/RESTReceiver.h
index f6373ef..159af7a 100644
--- a/extensions/http-curl/protocols/RESTReceiver.h
+++ b/extensions/http-curl/protocols/RESTReceiver.h
@@ -20,7 +20,6 @@
 #include <string>
 #include <mutex>
 #include <memory>
-#include "core/Resource.h"
 #include "c2/protocols/RESTProtocol.h"
 #include "CivetServer.h"
 #include "c2/C2Protocol.h"
@@ -92,8 +91,6 @@ class RESTReceiver : public RESTProtocol, public HeartbeatReporter {
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(RESTReceiver, "Provides a webserver to display C2 heartbeat information");
-
 } /* namespace c2 */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/http-curl/protocols/RESTSender.cpp b/extensions/http-curl/protocols/RESTSender.cpp
index 78e5155..d4a487c 100644
--- a/extensions/http-curl/protocols/RESTSender.cpp
+++ b/extensions/http-curl/protocols/RESTSender.cpp
@@ -24,6 +24,7 @@
 #include <vector>
 #include <limits>
 #include "utils/file/FileUtils.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -153,6 +154,8 @@ const C2Payload RESTSender::sendPayload(const std::string url, const Direction d
   }
 }
 
+REGISTER_RESOURCE(RESTSender, "Encapsulates the restful protocol that is built upon C2Protocol.");
+
 } /* namespace c2 */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/http-curl/protocols/RESTSender.h b/extensions/http-curl/protocols/RESTSender.h
index aaf4188..9189ebe 100644
--- a/extensions/http-curl/protocols/RESTSender.h
+++ b/extensions/http-curl/protocols/RESTSender.h
@@ -71,8 +71,6 @@ class RESTSender : public RESTProtocol, public C2Protocol {
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(RESTSender, "Encapsulates the restful protocol that is built upon C2Protocol.");
-
 }  // namespace c2
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/http-curl/sitetosite/HTTPProtocol.cpp b/extensions/http-curl/sitetosite/HTTPProtocol.cpp
index f198b59..d6902e5 100644
--- a/extensions/http-curl/sitetosite/HTTPProtocol.cpp
+++ b/extensions/http-curl/sitetosite/HTTPProtocol.cpp
@@ -31,6 +31,7 @@
 #include "io/CRCStream.h"
 #include "sitetosite/Peer.h"
 #include "io/validation.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -304,6 +305,8 @@ void HttpSiteToSiteClient::deleteTransaction(const utils::Identifier& transactio
   SiteToSiteClient::deleteTransaction(transactionID);
 }
 
+REGISTER_INTERNAL_RESOURCE_AS(HttpSiteToSiteClient, ("HttpSiteToSiteClient", "HttpProtocol"));
+
 } /* namespace sitetosite */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/http-curl/tests/C2PauseResumeTest.cpp b/extensions/http-curl/tests/C2PauseResumeTest.cpp
index 08e63e0..aee973b 100644
--- a/extensions/http-curl/tests/C2PauseResumeTest.cpp
+++ b/extensions/http-curl/tests/C2PauseResumeTest.cpp
@@ -128,7 +128,7 @@ int main(int argc, char **argv) {
     test_repo, test_repo, content_repo, stream_factory, configuration, args.test_file);
 
   std::shared_ptr<minifi::FlowController> controller = std::make_shared<minifi::FlowController>(
-      test_repo, test_flow_repo, configuration, std::move(yaml_ptr), content_repo, DEFAULT_ROOT_GROUP_NAME, true);
+      test_repo, test_flow_repo, configuration, std::move(yaml_ptr), content_repo, DEFAULT_ROOT_GROUP_NAME);
 
   core::YamlConfiguration yaml_config(test_repo, test_repo, content_repo, stream_factory, configuration, args.test_file);
 
diff --git a/extensions/http-curl/tests/CMakeLists.txt b/extensions/http-curl/tests/CMakeLists.txt
index d31e400..02ca8ec 100644
--- a/extensions/http-curl/tests/CMakeLists.txt
+++ b/extensions/http-curl/tests/CMakeLists.txt
@@ -36,9 +36,9 @@ FOREACH(testfile ${CURL_UNIT_TESTS})
 	target_include_directories(${testfilename} BEFORE PRIVATE ./include)
 	createTests("${testfilename}")
 	target_link_libraries(${testfilename} ${CATCH_MAIN_LIB})
-	target_wholearchive_library(${testfilename} minifi-http-curl)
-	target_wholearchive_library(${testfilename} minifi-civet-extensions)
-	target_wholearchive_library(${testfilename} minifi-standard-processors)
+	target_link_libraries(${testfilename} minifi-http-curl)
+	target_link_libraries(${testfilename} minifi-civet-extensions)
+	target_link_libraries(${testfilename} minifi-standard-processors)
 
 	MATH(EXPR CURL_INT_TEST_COUNT "${CURL_INT_TEST_COUNT}+1")
 	add_test(NAME "${testfilename}" COMMAND "${testfilename}" WORKING_DIRECTORY ${TEST_DIR})
@@ -57,9 +57,9 @@ FOREACH(testfile ${CURL_INTEGRATION_TESTS})
 	target_include_directories(${testfilename} BEFORE PRIVATE "${CMAKE_SOURCE_DIR}/extensions/civetweb/")
 	target_include_directories(${testfilename} BEFORE PRIVATE ./include)
 	createTests("${testfilename}")
-	target_wholearchive_library(${testfilename} minifi-http-curl)
-	target_wholearchive_library(${testfilename} minifi-civet-extensions)
-	target_wholearchive_library(${testfilename} minifi-standard-processors)
+	target_link_libraries(${testfilename} minifi-http-curl)
+	target_link_libraries(${testfilename} minifi-civet-extensions)
+	target_link_libraries(${testfilename} minifi-standard-processors)
 
 	MATH(EXPR CURL_INT_TEST_COUNT "${CURL_INT_TEST_COUNT}+1")
 ENDFOREACH()
diff --git a/extensions/http-curl/tests/ControllerServiceIntegrationTests.cpp b/extensions/http-curl/tests/ControllerServiceIntegrationTests.cpp
index efb6dcd..0a00fec 100644
--- a/extensions/http-curl/tests/ControllerServiceIntegrationTests.cpp
+++ b/extensions/http-curl/tests/ControllerServiceIntegrationTests.cpp
@@ -16,6 +16,8 @@
  * limitations under the License.
  */
 
+#define EXTENSION_LIST "*minifi-*,!*jni*"
+
 #undef NDEBUG
 #include <cassert>
 #include <chrono>
@@ -73,8 +75,7 @@ int main(int argc, char **argv) {
 
   std::shared_ptr<minifi::FlowController> controller = std::make_shared<minifi::FlowController>(test_repo, test_flow_repo, configuration, std::move(yaml_ptr),
                                                                                                 content_repo,
-                                                                                                DEFAULT_ROOT_GROUP_NAME,
-                                                                                                true);
+                                                                                                DEFAULT_ROOT_GROUP_NAME);
 
   disabled = false;
   std::shared_ptr<core::controller::ControllerServiceMap> map = std::make_shared<core::controller::ControllerServiceMap>();
diff --git a/extensions/http-curl/tests/VerifyInvokeHTTP.h b/extensions/http-curl/tests/VerifyInvokeHTTP.h
index 725273b..3cd46b7 100644
--- a/extensions/http-curl/tests/VerifyInvokeHTTP.h
+++ b/extensions/http-curl/tests/VerifyInvokeHTTP.h
@@ -86,7 +86,7 @@ class VerifyInvokeHTTP : public HTTPIntegrationBase {
     content_repo->initialize(configuration);
     std::shared_ptr<minifi::io::StreamFactory> stream_factory = minifi::io::StreamFactory::getInstance(configuration);
     auto yaml_ptr = std::make_unique<core::YamlConfiguration>(test_repo, test_repo, content_repo, stream_factory, configuration, flow_yml_path);
-    flowController_ = std::make_shared<minifi::FlowController>(test_repo, test_flow_repo, configuration, std::move(yaml_ptr), content_repo, DEFAULT_ROOT_GROUP_NAME, true);
+    flowController_ = std::make_shared<minifi::FlowController>(test_repo, test_flow_repo, configuration, std::move(yaml_ptr), content_repo, DEFAULT_ROOT_GROUP_NAME);
     flowController_->load();
 
     std::string url = scheme + "://localhost:" + getWebPort() + *path_;
diff --git a/extensions/jni/CMakeLists.txt b/extensions/jni/CMakeLists.txt
index 081d317..e0bb21a 100644
--- a/extensions/jni/CMakeLists.txt
+++ b/extensions/jni/CMakeLists.txt
@@ -28,8 +28,7 @@ include_directories(${JNI_INCLUDE_DIRS})
 
 file(GLOB SOURCES  "jvm/*.cpp" "*.cpp")
 
-add_library(minifi-jni STATIC ${SOURCES})
-set_property(TARGET minifi-jni PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-jni SHARED ${SOURCES})
 
 set(JNI_FRAMEWORK_JAR_SOURCE "${CMAKE_SOURCE_DIR}/extensions/jni/nifi-framework-jni")
 set(JNI_FRAMEWORK_JAR_BIN "${CMAKE_CURRENT_BINARY_DIR}/" )
diff --git a/extensions/jni/ClassRegistrar.h b/extensions/jni/ClassRegistrar.h
index 8afdeea..74505cf 100644
--- a/extensions/jni/ClassRegistrar.h
+++ b/extensions/jni/ClassRegistrar.h
@@ -27,7 +27,6 @@
 #include "core/ProcessSession.h"
 #include "core/Core.h"
 #include "core/Property.h"
-#include "core/Resource.h"
 #include "concurrentqueue.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "jvm/JavaControllerService.h"
diff --git a/extensions/jni/ExecuteJavaControllerService.cpp b/extensions/jni/ExecuteJavaControllerService.cpp
index a2cbf1f..bf448e8 100644
--- a/extensions/jni/ExecuteJavaControllerService.cpp
+++ b/extensions/jni/ExecuteJavaControllerService.cpp
@@ -36,6 +36,7 @@
 #include "core/logging/Logger.h"
 #include "core/ProcessContext.h"
 #include "core/Relationship.h"
+#include "core/Resource.h"
 #include "ResourceClaim.h"
 #include "utils/StringUtils.h"
 #include "utils/ByteArrayCallback.h"
@@ -105,6 +106,8 @@ void ExecuteJavaControllerService::onEnable() {
   }
 }
 
+REGISTER_RESOURCE(ExecuteJavaControllerService, "ExecuteJavaClass runs NiFi Controller services given a provided system path ");
+
 } /* namespace controllers */
 } /* namespace jni */
 } /* namespace minifi */
diff --git a/extensions/jni/ExecuteJavaControllerService.h b/extensions/jni/ExecuteJavaControllerService.h
index 5493f79..1178af2 100644
--- a/extensions/jni/ExecuteJavaControllerService.h
+++ b/extensions/jni/ExecuteJavaControllerService.h
@@ -27,7 +27,6 @@
 #include "core/ProcessSession.h"
 #include "core/Core.h"
 #include "core/Property.h"
-#include "core/Resource.h"
 #include "concurrentqueue.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "jvm/JavaControllerService.h"
@@ -151,8 +150,6 @@ class ExecuteJavaControllerService : public ConfigurationContext, public std::en
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(ExecuteJavaControllerService, "ExecuteJavaClass runs NiFi Controller services given a provided system path ");
-
 } /* namespace controllers */
 } /* namespace jni */
 } /* namespace minifi */
diff --git a/extensions/jni/ExecuteJavaProcessor.cpp b/extensions/jni/ExecuteJavaProcessor.cpp
index e7b28ae..30e9237 100644
--- a/extensions/jni/ExecuteJavaProcessor.cpp
+++ b/extensions/jni/ExecuteJavaProcessor.cpp
@@ -36,6 +36,7 @@
 #include "core/logging/Logger.h"
 #include "core/ProcessContext.h"
 #include "core/Relationship.h"
+#include "core/Resource.h"
 #include "ResourceClaim.h"
 #include "utils/StringUtils.h"
 #include "utils/ByteArrayCallback.h"
@@ -232,6 +233,8 @@ void ExecuteJavaProcessor::onTrigger(const std::shared_ptr<core::ProcessContext>
   // do nothing.
 }
 
+REGISTER_RESOURCE_AS(ExecuteJavaProcessor, "ExecuteJavaClass runs NiFi processors given a provided system path ", ("ExecuteJavaClass"));
+
 } /* namespace processors */
 } /* namespace jni */
 } /* namespace minifi */
diff --git a/extensions/jni/ExecuteJavaProcessor.h b/extensions/jni/ExecuteJavaProcessor.h
index f835ee7..86e3e1b 100644
--- a/extensions/jni/ExecuteJavaProcessor.h
+++ b/extensions/jni/ExecuteJavaProcessor.h
@@ -27,7 +27,6 @@
 #include "core/ProcessSession.h"
 #include "core/Core.h"
 #include "core/Property.h"
-#include "core/Resource.h"
 #include "concurrentqueue.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "jvm/JavaControllerService.h"
@@ -296,8 +295,6 @@ class ExecuteJavaProcessor : public core::Processor {
   JniInitializationContext init_context_;
 };
 
-REGISTER_RESOURCE(ExecuteJavaProcessor, "ExecuteJavaClass runs NiFi processors given a provided system path ");
-
 } /* namespace processors */
 } /* namespace jni */
 } /* namespace minifi */
diff --git a/extensions/jni/JNILoader.cpp b/extensions/jni/JNILoader.cpp
index 2177298..ec15661 100644
--- a/extensions/jni/JNILoader.cpp
+++ b/extensions/jni/JNILoader.cpp
@@ -15,16 +15,24 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include "JNILoader.h"
 
-#include "core/FlowConfiguration.h"
+#include "core/extension/Extension.h"
+#include "JVMCreator.h"
 
-bool JNIFactory::added = core::FlowConfiguration::add_static_func("createJNIFactory");
+namespace minifi = org::apache::nifi::minifi;
 
-extern "C" {
+static minifi::jni::JVMCreator& getJVMCreator() {
+  static minifi::jni::JVMCreator instance("JVMCreator");
+  return instance;
+}
 
-void *createJNIFactory(void) {
-  return new JNIFactory();
+static bool init(const std::shared_ptr<org::apache::nifi::minifi::Configure>& config) {
+  getJVMCreator().configure(config);
+  return true;
 }
 
+static void deinit() {
+  // TODO(adebreceni): deinitialization is not implemented
 }
+
+REGISTER_EXTENSION("JNIExtension", init, deinit);
diff --git a/extensions/jni/JNILoader.h b/extensions/jni/JNILoader.h
deleted file mode 100644
index 6a0dc03..0000000
--- a/extensions/jni/JNILoader.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <vector>
-#include <string>
-#include <memory>
-
-#include "core/ClassLoader.h"
-#include "ExecuteJavaProcessor.h"
-#include "ExecuteJavaControllerService.h"
-#include "JVMCreator.h"
-#include "jvm/JavaControllerService.h"
-#include "utils/StringUtils.h"
-
-class JNIFactory : public core::ObjectFactory {
- public:
-  JNIFactory() = default;
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  virtual std::string getName() {
-    return "JNIFactory";
-  }
-
-  virtual std::string getClassName() {
-    return "JNIFactory";
-  }
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  virtual std::vector<std::string> getClassNames() {
-    static std::vector<std::string> class_names;
-    if (class_names.empty()) {
-      class_names.push_back("ExecuteJavaClass");
-      class_names.push_back("JavaControllerService");
-      class_names.push_back("JVMCreator");
-    }
-    return class_names;
-  }
-
-  virtual std::unique_ptr<ObjectFactory> assign(const std::string &class_name) {
-    if (utils::StringUtils::equalsIgnoreCase(class_name, "ExecuteJavaClass")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::jni::processors::ExecuteJavaProcessor>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "JavaControllerService")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::jni::controllers::JavaControllerService>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "ExecuteJavaControllerService")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::jni::controllers::ExecuteJavaControllerService>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "JVMCreator")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::jni::JVMCreator>());
-    }
-    return nullptr;
-  }
-
-  static minifi::jni::JVMLoader jvm;
-
-  static bool added;
-};
-
-extern "C" {
-DLL_EXPORT void *createJNIFactory(void);
-}
diff --git a/extensions/jni/JVMCreator.cpp b/extensions/jni/JVMCreator.cpp
index 5f386b9..239fc96 100644
--- a/extensions/jni/JVMCreator.cpp
+++ b/extensions/jni/JVMCreator.cpp
@@ -17,6 +17,7 @@
  */
 
 #include "JVMCreator.h"
+#include "core/Resource.h"
 
 #ifndef WIN32
 
@@ -40,6 +41,8 @@ namespace jni {
 #endif
 JVMCreator::~JVMCreator() = default;
 
+REGISTER_INTERNAL_RESOURCE(JVMCreator);
+
 } /* namespace jni */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/jni/jvm/JavaControllerService.cpp b/extensions/jni/jvm/JavaControllerService.cpp
index 1686c20..560e8a7 100644
--- a/extensions/jni/jvm/JavaControllerService.cpp
+++ b/extensions/jni/jvm/JavaControllerService.cpp
@@ -24,6 +24,7 @@
 #include <iterator>
 #include <set>
 #include "core/Property.h"
+#include "core/Resource.h"
 #include "io/validation.h"
 #include "utils/StringUtils.h"
 #include "utils/file/FileUtils.h"
@@ -108,6 +109,8 @@ void JavaControllerService::onEnable() {
   nar_loader_ = std::unique_ptr<NarClassLoader>(new NarClassLoader(shared_from_this(), narClassLoaderClazz, nardir, narscratch, nardocs));
 }
 
+REGISTER_RESOURCE(JavaControllerService, "Allows specification of nars to be used within referenced processors. ");
+
 } /* namespace controllers */
 } /* namespace jni */
 } /* namespace minifi */
diff --git a/extensions/jni/jvm/JavaControllerService.h b/extensions/jni/jvm/JavaControllerService.h
index 42f92bc..9fec2df 100644
--- a/extensions/jni/jvm/JavaControllerService.h
+++ b/extensions/jni/jvm/JavaControllerService.h
@@ -26,7 +26,6 @@
 
 #include "../jvm/JVMLoader.h"
 #include "NarClassLoader.h"
-#include "core/Resource.h"
 #include "utils/StringUtils.h"
 #include "JavaServicer.h"
 #include "io/validation.h"
@@ -160,8 +159,6 @@ class JavaControllerService : public core::controller::ControllerService, public
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(JavaControllerService, "Allows specification of nars to be used within referenced processors. ");
-
 } /* namespace controllers */
 } /* namespace jni */
 } /* namespace minifi */
diff --git a/extensions/jni/jvm/JniProcessContext.h b/extensions/jni/jvm/JniProcessContext.h
index 17d45ed..c1a05ff 100644
--- a/extensions/jni/jvm/JniProcessContext.h
+++ b/extensions/jni/jvm/JniProcessContext.h
@@ -61,15 +61,15 @@ struct JniProcessContext {
 extern "C" {
 #endif
 
-DLL_EXPORT jstring JNICALL Java_org_apache_nifi_processor_JniProcessContext_getPropertyValue(JNIEnv *env, jobject obj, jstring propertyName);
+jstring JNICALL Java_org_apache_nifi_processor_JniProcessContext_getPropertyValue(JNIEnv *env, jobject obj, jstring propertyName);
 
-DLL_EXPORT jobject JNICALL Java_org_apache_nifi_processor_JniProcessContext_getPropertyNames(JNIEnv *env, jobject obj);
+jobject JNICALL Java_org_apache_nifi_processor_JniProcessContext_getPropertyNames(JNIEnv *env, jobject obj);
 
-DLL_EXPORT jobject JNICALL Java_org_apache_nifi_processor_JniProcessContext_getComponent(JNIEnv *env, jobject obj);
+jobject JNICALL Java_org_apache_nifi_processor_JniProcessContext_getComponent(JNIEnv *env, jobject obj);
 
-DLL_EXPORT jstring JNICALL Java_org_apache_nifi_processor_JniProcessContext_getName(JNIEnv *env, jobject obj);
+jstring JNICALL Java_org_apache_nifi_processor_JniProcessContext_getName(JNIEnv *env, jobject obj);
 
-DLL_EXPORT jobject JNICALL Java_org_apache_nifi_processor_JniProcessContext_getControllerServiceLookup(JNIEnv *env, jobject obj);
+jobject JNICALL Java_org_apache_nifi_processor_JniProcessContext_getControllerServiceLookup(JNIEnv *env, jobject obj);
 
 #ifdef __cplusplus
 }
diff --git a/extensions/jni/jvm/NarClassLoader.h b/extensions/jni/jvm/NarClassLoader.h
index 5173767..874cc87 100644
--- a/extensions/jni/jvm/NarClassLoader.h
+++ b/extensions/jni/jvm/NarClassLoader.h
@@ -31,6 +31,7 @@
 #include "JavaServicer.h"
 #include "JniBundle.h"
 #include "../JavaException.h"
+#include "agent/agent_docs.h"
 
 namespace org {
 namespace apache {
@@ -228,7 +229,7 @@ class NarClassLoader {
           lastOfIdx++;  // if a value is found, increment to move beyond the .
           int nameLength = cd.class_name_.length() - lastOfIdx;
           const auto processorName = cd.class_name_.substr(lastOfIdx, nameLength);
-          if (core::ClassLoader::getDefaultClassLoader().getGroupForClass(processorName).empty()) {
+          if (!core::ClassLoader::getDefaultClassLoader().getGroupForClass(processorName)) {
             minifi::ExternalBuildDescription::addExternalComponent(bundle.getDetails(), cd);
           }
         }
diff --git a/extensions/libarchive/ArchiveLoader.h b/extensions/libarchive/ArchiveLoader.h
deleted file mode 100644
index 2a71aeb..0000000
--- a/extensions/libarchive/ArchiveLoader.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <vector>
-#include <string>
-#include <memory>
-
-#include "MergeContent.h"
-#include "CompressContent.h"
-#include "FocusArchiveEntry.h"
-#include "UnfocusArchiveEntry.h"
-#include "ManipulateArchive.h"
-#include "core/ClassLoader.h"
-
-class ArchiveFactory : public core::ObjectFactory {
- public:
-  ArchiveFactory() = default;
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  virtual std::string getName() {
-    return "ArchiveFactory";
-  }
-
-  virtual std::string getClassName() {
-    return "ArchiveFactory";
-  }
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  virtual std::vector<std::string> getClassNames() {
-    std::vector<std::string> class_names;
-    class_names.push_back("MergeContent");
-    class_names.push_back("CompressContent");
-    class_names.push_back("FocusArchiveEntry");
-    class_names.push_back("UnfocusArchiveEntry");
-    class_names.push_back("ManipulateArchive");
-    return class_names;
-  }
-
-  virtual std::unique_ptr<ObjectFactory> assign(const std::string &class_name) {
-    if (utils::StringUtils::equalsIgnoreCase(class_name, "MergeContent")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::processors::MergeContent>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "CompressContent")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::processors::CompressContent>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "FocusArchiveEntry")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::processors::FocusArchiveEntry>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "UnfocusArchiveEntry")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::processors::UnfocusArchiveEntry>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "ManipulateArchive")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::processors::ManipulateArchive>());
-    } else {
-      return nullptr;
-    }
-  }
-
-  static bool added;
-};
-
-extern "C" {
-void *createArchiveFactory(void);
-}
diff --git a/extensions/libarchive/BinFiles.cpp b/extensions/libarchive/BinFiles.cpp
index 3b12026..160b474 100644
--- a/extensions/libarchive/BinFiles.cpp
+++ b/extensions/libarchive/BinFiles.cpp
@@ -30,6 +30,7 @@
 #include "utils/StringUtils.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -374,6 +375,8 @@ std::set<std::shared_ptr<core::Connectable>> BinFiles::getOutGoingConnections(co
   return result;
 }
 
+REGISTER_RESOURCE(BinFiles, "Bins flow files into buckets based on the number of entries or size of entries");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/libarchive/BinFiles.h b/extensions/libarchive/BinFiles.h
index 40b6bb7..438c109 100644
--- a/extensions/libarchive/BinFiles.h
+++ b/extensions/libarchive/BinFiles.h
@@ -30,10 +30,10 @@
 #include "FlowFileRecord.h"
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
-#include "core/Resource.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "utils/gsl.h"
 #include "utils/Id.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -211,28 +211,28 @@ class BinFiles : public core::Processor {
   // Processor Name
   static constexpr char const* ProcessorName = "BinFiles";
   // Supported Properties
-  static core::Property MinSize;
-  static core::Property MaxSize;
-  static core::Property MinEntries;
-  static core::Property MaxEntries;
-  static core::Property MaxBinCount;
-  static core::Property MaxBinAge;
-  static core::Property BatchSize;
+  EXTENSIONAPI static core::Property MinSize;
+  EXTENSIONAPI static core::Property MaxSize;
+  EXTENSIONAPI static core::Property MinEntries;
+  EXTENSIONAPI static core::Property MaxEntries;
+  EXTENSIONAPI static core::Property MaxBinCount;
+  EXTENSIONAPI static core::Property MaxBinAge;
+  EXTENSIONAPI static core::Property BatchSize;
 
   // Supported Relationships
-  static core::Relationship Failure;
-  static core::Relationship Original;
+  EXTENSIONAPI static core::Relationship Failure;
+  EXTENSIONAPI static core::Relationship Original;
 
   // attributes
-  static const char *FRAGMENT_ID_ATTRIBUTE;
-  static const char *FRAGMENT_INDEX_ATTRIBUTE;
-  static const char *FRAGMENT_COUNT_ATTRIBUTE;
+  EXTENSIONAPI static const char *FRAGMENT_ID_ATTRIBUTE;
+  EXTENSIONAPI static const char *FRAGMENT_INDEX_ATTRIBUTE;
+  EXTENSIONAPI static const char *FRAGMENT_COUNT_ATTRIBUTE;
 
-  static const char *SEGMENT_ID_ATTRIBUTE;
-  static const char *SEGMENT_INDEX_ATTRIBUTE;
-  static const char *SEGMENT_COUNT_ATTRIBUTE;
-  static const char *SEGMENT_ORIGINAL_FILENAME;
-  static const char *TAR_PERMISSIONS_ATTRIBUTE;
+  EXTENSIONAPI static const char *SEGMENT_ID_ATTRIBUTE;
+  EXTENSIONAPI static const char *SEGMENT_INDEX_ATTRIBUTE;
+  EXTENSIONAPI static const char *SEGMENT_COUNT_ATTRIBUTE;
+  EXTENSIONAPI static const char *SEGMENT_ORIGINAL_FILENAME;
+  EXTENSIONAPI static const char *TAR_PERMISSIONS_ATTRIBUTE;
 
  public:
   /**
@@ -293,8 +293,6 @@ class BinFiles : public core::Processor {
   FlowFileStore file_store_;
 };
 
-REGISTER_RESOURCE(BinFiles, "Bins flow files into buckets based on the number of entries or size of entries");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/libarchive/CMakeLists.txt b/extensions/libarchive/CMakeLists.txt
index 8cb361e..71f0f88 100644
--- a/extensions/libarchive/CMakeLists.txt
+++ b/extensions/libarchive/CMakeLists.txt
@@ -21,8 +21,7 @@ include(${CMAKE_SOURCE_DIR}/extensions/ExtensionHeader.txt)
 
 file(GLOB SOURCES  "*.cpp")
 
-add_library(minifi-archive-extensions STATIC ${SOURCES})
-set_property(TARGET minifi-archive-extensions PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-archive-extensions SHARED ${SOURCES})
 
 target_link_libraries(minifi-archive-extensions ${LIBMINIFI} Threads::Threads)
 target_link_libraries(minifi-archive-extensions LibArchive::LibArchive)
diff --git a/extensions/libarchive/CompressContent.cpp b/extensions/libarchive/CompressContent.cpp
index 08e3201..12e2016 100644
--- a/extensions/libarchive/CompressContent.cpp
+++ b/extensions/libarchive/CompressContent.cpp
@@ -26,6 +26,7 @@
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
 #include "utils/StringUtils.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -227,6 +228,8 @@ std::string CompressContent::toMimeType(CompressionFormat format) {
   throw Exception(GENERAL_EXCEPTION, "Invalid compression format");
 }
 
+REGISTER_RESOURCE(CompressContent, "Compresses or decompresses the contents of FlowFiles using a user-specified compression algorithm and updates the mime.type attribute as appropriate");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/libarchive/CompressContent.h b/extensions/libarchive/CompressContent.h
index 4b3b791..9bbe6ed 100644
--- a/extensions/libarchive/CompressContent.h
+++ b/extensions/libarchive/CompressContent.h
@@ -33,12 +33,12 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Core.h"
-#include "core/Resource.h"
 #include "core/Property.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "io/ZlibStream.h"
 #include "utils/Enum.h"
 #include "utils/gsl.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -62,18 +62,18 @@ class CompressContent : public core::Processor {
   // Destructor
   ~CompressContent() override = default;
   // Processor Name
-  static constexpr char const* ProcessorName = "CompressContent";
+  EXTENSIONAPI static constexpr char const* ProcessorName = "CompressContent";
   // Supported Properties
-  static core::Property CompressMode;
-  static core::Property CompressLevel;
-  static core::Property CompressFormat;
-  static core::Property UpdateFileName;
-  static core::Property EncapsulateInTar;
-  static core::Property BatchSize;
+  EXTENSIONAPI static core::Property CompressMode;
+  EXTENSIONAPI static core::Property CompressLevel;
+  EXTENSIONAPI static core::Property CompressFormat;
+  EXTENSIONAPI static core::Property UpdateFileName;
+  EXTENSIONAPI static core::Property EncapsulateInTar;
+  EXTENSIONAPI static core::Property BatchSize;
 
   // Supported Relationships
-  static core::Relationship Failure;
-  static core::Relationship Success;
+  EXTENSIONAPI static core::Relationship Failure;
+  EXTENSIONAPI static core::Relationship Success;
 
   static const std::string TAR_EXT;
 
@@ -455,8 +455,6 @@ class CompressContent : public core::Processor {
   static const std::map<CompressionFormat, std::string> fileExtension_;
 };
 
-REGISTER_RESOURCE(CompressContent, "Compresses or decompresses the contents of FlowFiles using a user-specified compression algorithm and updates the mime.type attribute as appropriate");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/libarchive/FocusArchiveEntry.cpp b/extensions/libarchive/FocusArchiveEntry.cpp
index 3a4e91c..0a31ab8 100644
--- a/extensions/libarchive/FocusArchiveEntry.cpp
+++ b/extensions/libarchive/FocusArchiveEntry.cpp
@@ -31,6 +31,7 @@
 
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 #include "Exception.h"
 #include "utils/gsl.h"
 
@@ -256,6 +257,10 @@ FocusArchiveEntry::ReadCallback::ReadCallback(core::Processor *processor, fileut
 
 FocusArchiveEntry::ReadCallback::~ReadCallback() = default;
 
+REGISTER_RESOURCE(FocusArchiveEntry, "Allows manipulation of entries within an archive (e.g. TAR) by focusing on one entry within the archive at a time. "
+    "When an archive entry is focused, that entry is treated as the content of the FlowFile and may be manipulated independently of the rest of the archive."
+    " To restore the FlowFile to its original state, use UnfocusArchiveEntry.");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/libarchive/FocusArchiveEntry.h b/extensions/libarchive/FocusArchiveEntry.h
index bee6dcc..314d5b8 100644
--- a/extensions/libarchive/FocusArchiveEntry.h
+++ b/extensions/libarchive/FocusArchiveEntry.h
@@ -30,8 +30,8 @@
 #include "core/ProcessSession.h"
 #include "core/Core.h"
 #include "core/logging/LoggerConfiguration.h"
-#include "core/Resource.h"
 #include "utils/file/FileManager.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -53,11 +53,11 @@ class FocusArchiveEntry : public core::Processor {
   //! Destructor
   virtual ~FocusArchiveEntry()   = default;
   //! Processor Name
-  static constexpr char const* ProcessorName = "FocusArchiveEntry";
+  EXTENSIONAPI static constexpr char const* ProcessorName = "FocusArchiveEntry";
   //! Supported Properties
-  static core::Property Path;
+  EXTENSIONAPI static core::Property Path;
   //! Supported Relationships
-  static core::Relationship Success;
+  EXTENSIONAPI static core::Relationship Success;
 
   //! OnTrigger method, implemented by NiFi FocusArchiveEntry
   virtual void onTrigger(core::ProcessContext *context,
@@ -87,10 +87,6 @@ class FocusArchiveEntry : public core::Processor {
   static std::shared_ptr<utils::IdGenerator> id_generator_;
 };
 
-REGISTER_RESOURCE(FocusArchiveEntry, "Allows manipulation of entries within an archive (e.g. TAR) by focusing on one entry within the archive at a time. "
-    "When an archive entry is focused, that entry is treated as the content of the FlowFile and may be manipulated independently of the rest of the archive."
-    " To restore the FlowFile to its original state, use UnfocusArchiveEntry.");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/libarchive/ManipulateArchive.cpp b/extensions/libarchive/ManipulateArchive.cpp
index f553103..99b31a9 100644
--- a/extensions/libarchive/ManipulateArchive.cpp
+++ b/extensions/libarchive/ManipulateArchive.cpp
@@ -32,6 +32,7 @@
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
 #include "core/FlowFile.h"
+#include "core/Resource.h"
 #include "utils/file/FileManager.h"
 #include "FocusArchiveEntry.h"
 #include "UnfocusArchiveEntry.h"
@@ -215,6 +216,8 @@ void ManipulateArchive::onTrigger(core::ProcessContext* /*context*/, core::Proce
     session->transfer(flowFile, Success);
 }
 
+REGISTER_RESOURCE(ManipulateArchive, "Performs an operation which manipulates an archive without needing to split the archive into multiple FlowFiles.");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/libarchive/ManipulateArchive.h b/extensions/libarchive/ManipulateArchive.h
index d3927ca..f49b077 100644
--- a/extensions/libarchive/ManipulateArchive.h
+++ b/extensions/libarchive/ManipulateArchive.h
@@ -27,6 +27,7 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -43,23 +44,23 @@ class ManipulateArchive : public core::Processor {
     logger_(logging::LoggerFactory<ManipulateArchive>::getLogger()) {
   }
   virtual ~ManipulateArchive() = default;
-  static constexpr char const* ProcessorName = "ManipulateArchive";
+  EXTENSIONAPI static constexpr char const* ProcessorName = "ManipulateArchive";
 
   // Supported operations
-  static char const* OPERATION_REMOVE;
-  static char const* OPERATION_COPY;
-  static char const* OPERATION_MOVE;
-  static char const* OPERATION_TOUCH;
+  EXTENSIONAPI static char const* OPERATION_REMOVE;
+  EXTENSIONAPI static char const* OPERATION_COPY;
+  EXTENSIONAPI static char const* OPERATION_MOVE;
+  EXTENSIONAPI static char const* OPERATION_TOUCH;
 
   // Supported Properties
-  static core::Property Operation;
-  static core::Property Target;
-  static core::Property Destination;
-  static core::Property Before;
-  static core::Property After;
+  EXTENSIONAPI static core::Property Operation;
+  EXTENSIONAPI static core::Property Target;
+  EXTENSIONAPI static core::Property Destination;
+  EXTENSIONAPI static core::Property Before;
+  EXTENSIONAPI static core::Property After;
   // Supported Relationships
-  static core::Relationship Success;
-  static core::Relationship Failure;
+  EXTENSIONAPI static core::Relationship Success;
+  EXTENSIONAPI static core::Relationship Failure;
 
   // OnTrigger method, implemented by NiFi ManipulateArchive
   void onTrigger(core::ProcessContext *context, core::ProcessSession *session);
@@ -73,8 +74,6 @@ class ManipulateArchive : public core::Processor {
   std::string before_, after_, operation_, destination_, targetEntry_;
 };
 
-REGISTER_RESOURCE(ManipulateArchive, "Performs an operation which manipulates an archive without needing to split the archive into multiple FlowFiles.");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/libarchive/MergeContent.cpp b/extensions/libarchive/MergeContent.cpp
index 0400aa7..15a5086 100644
--- a/extensions/libarchive/MergeContent.cpp
+++ b/extensions/libarchive/MergeContent.cpp
@@ -30,6 +30,7 @@
 #include "utils/TimeUtil.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 #include "serialization/PayloadSerializer.h"
 #include "serialization/FlowFileV3Serializer.h"
 
@@ -434,6 +435,10 @@ void KeepAllUniqueAttributesMerger::processFlowFile(const std::shared_ptr<core::
   }
 }
 
+REGISTER_RESOURCE(MergeContent, "Merges a Group of FlowFiles together based on a user-defined strategy and packages them into a single FlowFile. "
+    "MergeContent should be configured with only one incoming connection as it won't create grouped Flow Files."
+    "This processor updates the mime.type attribute as appropriate.");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/libarchive/MergeContent.h b/extensions/libarchive/MergeContent.h
index 3d36652..29403ba 100644
--- a/extensions/libarchive/MergeContent.h
+++ b/extensions/libarchive/MergeContent.h
@@ -32,6 +32,7 @@
 #include "core/logging/LoggerConfiguration.h"
 #include "serialization/FlowFileSerializer.h"
 #include "utils/gsl.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -315,20 +316,20 @@ class MergeContent : public processors::BinFiles {
   // Destructor
   ~MergeContent() override = default;
   // Processor Name
-  static constexpr char const* ProcessorName = "MergeContent";
+  EXTENSIONAPI static constexpr char const* ProcessorName = "MergeContent";
   // Supported Properties
-  static core::Property MergeStrategy;
-  static core::Property MergeFormat;
-  static core::Property CorrelationAttributeName;
-  static core::Property DelimiterStrategy;
-  static core::Property KeepPath;
-  static core::Property Header;
-  static core::Property Footer;
-  static core::Property Demarcator;
-  static core::Property AttributeStrategy;
+  EXTENSIONAPI static core::Property MergeStrategy;
+  EXTENSIONAPI static core::Property MergeFormat;
+  EXTENSIONAPI static core::Property CorrelationAttributeName;
+  EXTENSIONAPI static core::Property DelimiterStrategy;
+  EXTENSIONAPI static core::Property KeepPath;
+  EXTENSIONAPI static core::Property Header;
+  EXTENSIONAPI static core::Property Footer;
+  EXTENSIONAPI static core::Property Demarcator;
+  EXTENSIONAPI static core::Property AttributeStrategy;
 
   // Supported Relationships
-  static core::Relationship Merge;
+  EXTENSIONAPI static core::Relationship Merge;
 
  public:
   /**
@@ -374,10 +375,6 @@ class MergeContent : public processors::BinFiles {
   std::string readContent(std::string path);
 };
 
-REGISTER_RESOURCE(MergeContent, "Merges a Group of FlowFiles together based on a user-defined strategy and packages them into a single FlowFile. "
-    "MergeContent should be configured with only one incoming connection as it won't create grouped Flow Files."
-    "This processor updates the mime.type attribute as appropriate.");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/libarchive/UnfocusArchiveEntry.cpp b/extensions/libarchive/UnfocusArchiveEntry.cpp
index cd33233..26d0e30 100644
--- a/extensions/libarchive/UnfocusArchiveEntry.cpp
+++ b/extensions/libarchive/UnfocusArchiveEntry.cpp
@@ -31,6 +31,7 @@
 
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 #include "utils/gsl.h"
 
 namespace org {
@@ -234,6 +235,8 @@ int64_t UnfocusArchiveEntry::WriteCallback::process(const std::shared_ptr<io::Ba
   return nlen;
 }
 
+REGISTER_RESOURCE(UnfocusArchiveEntry, "Restores a FlowFile which has had an archive entry focused via FocusArchiveEntry to its original state.");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/libarchive/UnfocusArchiveEntry.h b/extensions/libarchive/UnfocusArchiveEntry.h
index e74cad9..a36b82b 100644
--- a/extensions/libarchive/UnfocusArchiveEntry.h
+++ b/extensions/libarchive/UnfocusArchiveEntry.h
@@ -31,7 +31,6 @@
 #include "core/ProcessSession.h"
 #include "core/Core.h"
 #include "core/logging/LoggerConfiguration.h"
-#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -83,8 +82,6 @@ class UnfocusArchiveEntry : public core::Processor {
   std::shared_ptr<Logger> logger_;
 };
 
-REGISTER_RESOURCE(UnfocusArchiveEntry, "Restores a FlowFile which has had an archive entry focused via FocusArchiveEntry to its original state.");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/librdkafka/CMakeLists.txt b/extensions/librdkafka/CMakeLists.txt
index 8e8709d..df71212 100644
--- a/extensions/librdkafka/CMakeLists.txt
+++ b/extensions/librdkafka/CMakeLists.txt
@@ -21,8 +21,7 @@ include(${CMAKE_SOURCE_DIR}/extensions/ExtensionHeader.txt)
 
 file(GLOB SOURCES  "*.cpp")
 
-add_library(minifi-rdkafka-extensions STATIC ${SOURCES})
-set_property(TARGET minifi-rdkafka-extensions PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-rdkafka-extensions SHARED ${SOURCES})
 
 target_link_libraries(minifi-rdkafka-extensions ${LIBMINIFI} Threads::Threads)
 target_link_libraries(minifi-rdkafka-extensions librdkafka)
diff --git a/extensions/librdkafka/ConsumeKafka.cpp b/extensions/librdkafka/ConsumeKafka.cpp
index 69926d7..28151fe 100644
--- a/extensions/librdkafka/ConsumeKafka.cpp
+++ b/extensions/librdkafka/ConsumeKafka.cpp
@@ -21,6 +21,7 @@
 #include <limits>
 
 #include "core/PropertyValidation.h"
+#include "core/Resource.h"
 #include "utils/ProcessorConfigUtils.h"
 #include "utils/gsl.h"
 
@@ -574,6 +575,10 @@ int64_t ConsumeKafka::WriteCallback::process(const std::shared_ptr<io::BaseStrea
   return gsl::narrow<int64_t>(write_ret);
 }
 
+REGISTER_RESOURCE(ConsumeKafka, "Consumes messages from Apache Kafka and transform them into MiNiFi FlowFiles. "
+    "The application should make sure that the processor is triggered at regular intervals, even if no messages are expected, "
+    "to serve any queued callbacks waiting to be called. Rebalancing can also only happen on trigger."); // NOLINT
+
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/librdkafka/ConsumeKafka.h b/extensions/librdkafka/ConsumeKafka.h
index 61facaa..bfa47a9 100644
--- a/extensions/librdkafka/ConsumeKafka.h
+++ b/extensions/librdkafka/ConsumeKafka.h
@@ -37,28 +37,28 @@ namespace processors {
 
 class ConsumeKafka : public core::Processor {
  public:
-  static constexpr char const* ProcessorName = "ConsumeKafka";
+  EXTENSIONAPI static constexpr char const* ProcessorName = "ConsumeKafka";
 
   // Supported Properties
-  static core::Property KafkaBrokers;
-  static core::Property SecurityProtocol;
-  static core::Property TopicNames;
-  static core::Property TopicNameFormat;
-  static core::Property HonorTransactions;
-  static core::Property GroupID;
-  static core::Property OffsetReset;
-  static core::Property KeyAttributeEncoding;
-  static core::Property MessageDemarcator;
-  static core::Property MessageHeaderEncoding;
-  static core::Property HeadersToAddAsAttributes;
-  static core::Property DuplicateHeaderHandling;
-  static core::Property MaxPollRecords;
-  static core::Property MaxPollTime;
-  static core::Property SessionTimeout;
-  static core::Property SSLContextService;
+  EXTENSIONAPI static core::Property KafkaBrokers;
+  EXTENSIONAPI static core::Property SecurityProtocol;
+  EXTENSIONAPI static core::Property TopicNames;
+  EXTENSIONAPI static core::Property TopicNameFormat;
+  EXTENSIONAPI static core::Property HonorTransactions;
+  EXTENSIONAPI static core::Property GroupID;
+  EXTENSIONAPI static core::Property OffsetReset;
+  EXTENSIONAPI static core::Property KeyAttributeEncoding;
+  EXTENSIONAPI static core::Property MessageDemarcator;
+  EXTENSIONAPI static core::Property MessageHeaderEncoding;
+  EXTENSIONAPI static core::Property HeadersToAddAsAttributes;
+  EXTENSIONAPI static core::Property DuplicateHeaderHandling;
+  EXTENSIONAPI static core::Property MaxPollRecords;
+  EXTENSIONAPI static core::Property MaxPollTime;
+  EXTENSIONAPI static core::Property SessionTimeout;
+  EXTENSIONAPI static core::Property SSLContextService;
 
   // Supported Relationships
-  static const core::Relationship Success;
+  EXTENSIONAPI static const core::Relationship Success;
 
   // Security Protocol allowable values
   static constexpr char const* SECURITY_PROTOCOL_PLAINTEXT = "plaintext";
@@ -186,10 +186,6 @@ class ConsumeKafka : public core::Processor {
   std::shared_ptr<logging::Logger> logger_{logging::LoggerFactory<ConsumeKafka>::getLogger()};
 };
 
-REGISTER_RESOURCE(ConsumeKafka, "Consumes messages from Apache Kafka and transform them into MiNiFi FlowFiles. "
-    "The application should make sure that the processor is triggered at regular intervals, even if no messages are expected, "
-    "to serve any queued callbacks waiting to be called. Rebalancing can also only happen on trigger."); // NOLINT
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/librdkafka/PublishKafka.cpp b/extensions/librdkafka/PublishKafka.cpp
index ce9b0d6..905dac8 100644
--- a/extensions/librdkafka/PublishKafka.cpp
+++ b/extensions/librdkafka/PublishKafka.cpp
@@ -33,6 +33,7 @@
 #include "utils/StringUtils.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -1077,6 +1078,9 @@ void PublishKafka::onTrigger(const std::shared_ptr<core::ProcessContext> &contex
   });
 }
 
+REGISTER_RESOURCE(PublishKafka, "This Processor puts the contents of a FlowFile to a Topic in Apache Kafka. The content of a FlowFile becomes the contents of a Kafka message. "
+                  "This message is optionally assigned a key by using the <Kafka Key> Property.");
+
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/librdkafka/PublishKafka.h b/extensions/librdkafka/PublishKafka.h
index 787137b..ca0d26a 100644
--- a/extensions/librdkafka/PublishKafka.h
+++ b/extensions/librdkafka/PublishKafka.h
@@ -37,7 +37,6 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Core.h"
-#include "core/Resource.h"
 #include "core/Property.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "core/logging/Logger.h"
@@ -57,38 +56,38 @@ class PublishKafka : public core::Processor {
   static constexpr char const* ProcessorName = "PublishKafka";
 
   // Supported Properties
-  static const core::Property SeedBrokers;
-  static const core::Property Topic;
-  static const core::Property DeliveryGuarantee;
-  static const core::Property MaxMessageSize;
-  static const core::Property RequestTimeOut;
-  static const core::Property MessageTimeOut;
-  static const core::Property ClientName;
-  static const core::Property BatchSize;
-  static const core::Property TargetBatchPayloadSize;
-  static const core::Property AttributeNameRegex;
-  static const core::Property QueueBufferMaxTime;
-  static const core::Property QueueBufferMaxSize;
-  static const core::Property QueueBufferMaxMessage;
-  static const core::Property CompressCodec;
-  static const core::Property MaxFlowSegSize;
-  static const core::Property SSLContextService;
-  static const core::Property SecurityProtocol;
-  static const core::Property SecurityCA;
-  static const core::Property SecurityCert;
-  static const core::Property SecurityPrivateKey;
-  static const core::Property SecurityPrivateKeyPassWord;
-  static const core::Property KerberosServiceName;
-  static const core::Property KerberosPrincipal;
-  static const core::Property KerberosKeytabPath;
-  static const core::Property KafkaKey;
-  static const core::Property MessageKeyField;
-  static const core::Property DebugContexts;
-  static const core::Property FailEmptyFlowFiles;
+  EXTENSIONAPI static const core::Property SeedBrokers;
+  EXTENSIONAPI static const core::Property Topic;
+  EXTENSIONAPI static const core::Property DeliveryGuarantee;
+  EXTENSIONAPI static const core::Property MaxMessageSize;
+  EXTENSIONAPI static const core::Property RequestTimeOut;
+  EXTENSIONAPI static const core::Property MessageTimeOut;
+  EXTENSIONAPI static const core::Property ClientName;
+  EXTENSIONAPI static const core::Property BatchSize;
+  EXTENSIONAPI static const core::Property TargetBatchPayloadSize;
+  EXTENSIONAPI static const core::Property AttributeNameRegex;
+  EXTENSIONAPI static const core::Property QueueBufferMaxTime;
+  EXTENSIONAPI static const core::Property QueueBufferMaxSize;
+  EXTENSIONAPI static const core::Property QueueBufferMaxMessage;
+  EXTENSIONAPI static const core::Property CompressCodec;
+  EXTENSIONAPI static const core::Property MaxFlowSegSize;
+  EXTENSIONAPI static const core::Property SSLContextService;
+  EXTENSIONAPI static const core::Property SecurityProtocol;
+  EXTENSIONAPI static const core::Property SecurityCA;
+  EXTENSIONAPI static const core::Property SecurityCert;
+  EXTENSIONAPI static const core::Property SecurityPrivateKey;
+  EXTENSIONAPI static const core::Property SecurityPrivateKeyPassWord;
+  EXTENSIONAPI static const core::Property KerberosServiceName;
+  EXTENSIONAPI static const core::Property KerberosPrincipal;
+  EXTENSIONAPI static const core::Property KerberosKeytabPath;
+  EXTENSIONAPI static const core::Property KafkaKey;
+  EXTENSIONAPI static const core::Property MessageKeyField;
+  EXTENSIONAPI static const core::Property DebugContexts;
+  EXTENSIONAPI static const core::Property FailEmptyFlowFiles;
 
   // Supported Relationships
-  static const core::Relationship Failure;
-  static const core::Relationship Success;
+  EXTENSIONAPI static const core::Relationship Failure;
+  EXTENSIONAPI static const core::Relationship Success;
 
   explicit PublishKafka(const std::string& name, const utils::Identifier& uuid = {})
       : core::Processor(std::move(name), uuid) {
@@ -136,9 +135,6 @@ class PublishKafka : public core::Processor {
   std::set<std::shared_ptr<Messages>> messages_set_;
 };
 
-REGISTER_RESOURCE(PublishKafka, "This Processor puts the contents of a FlowFile to a Topic in Apache Kafka. The content of a FlowFile becomes the contents of a Kafka message. "
-                  "This message is optionally assigned a key by using the <Kafka Key> Property.");
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/librdkafka/RdKafkaLoader.cpp b/extensions/librdkafka/RdKafkaLoader.cpp
deleted file mode 100644
index 82b4b56..0000000
--- a/extensions/librdkafka/RdKafkaLoader.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "RdKafkaLoader.h"
-#include "core/FlowConfiguration.h"
-
-bool RdKafkaFactory::added = core::FlowConfiguration::add_static_func("createRdKafkaFactory");
-
-extern "C" {
-
-void *createRdKafkaFactory(void) {
-  return new RdKafkaFactory();
-}
-
-}
diff --git a/extensions/librdkafka/RdKafkaLoader.h b/extensions/librdkafka/RdKafkaLoader.h
deleted file mode 100644
index 309b834..0000000
--- a/extensions/librdkafka/RdKafkaLoader.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef EXTENSIONS_LIBRDKAFKA_RDKAFKALOADER_H_
-#define EXTENSIONS_LIBRDKAFKA_RDKAFKALOADER_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "PublishKafka.h"
-#include "core/ClassLoader.h"
-
-class RdKafkaFactory : public core::ObjectFactory {
- public:
-  RdKafkaFactory() = default;
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  virtual std::string getName() {
-    return "RdKafkaFactory";
-  }
-
-  virtual std::string getClassName() {
-    return "RdKafkaFactory";
-  }
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  virtual std::vector<std::string> getClassNames() {
-    std::vector<std::string> class_names;
-    class_names.push_back("PublishKafka");
-    return class_names;
-  }
-
-  virtual std::unique_ptr<ObjectFactory> assign(const std::string &class_name) {
-    if (utils::StringUtils::equalsIgnoreCase(class_name, "PublishKafka")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::processors::PublishKafka>());
-    } else {
-      return nullptr;
-    }
-  }
-
-  static bool added;
-};
-
-extern "C" {
-DLL_EXPORT void *createRdKafkaFactory(void);
-}
-#endif  // EXTENSIONS_LIBRDKAFKA_RDKAFKALOADER_H_
diff --git a/extensions/librdkafka/docker_tests/CMakeLists.txt b/extensions/librdkafka/docker_tests/CMakeLists.txt
index 2b1bdd8..6fe8a0a 100644
--- a/extensions/librdkafka/docker_tests/CMakeLists.txt
+++ b/extensions/librdkafka/docker_tests/CMakeLists.txt
@@ -25,7 +25,7 @@ FOREACH(testfile ${KAFKA_TESTS})
     get_filename_component(testfilename "${testfile}" NAME_WE)
     add_executable("${testfilename}" "${testfile}")
     target_include_directories(${testfilename} PRIVATE BEFORE "${CMAKE_SOURCE_DIR}/extensions/librdkafka/")
-    target_wholearchive_library(${testfilename} minifi-rdkafka-extensions)
+    target_link_libraries(${testfilename} minifi-rdkafka-extensions)
     createTests("${testfilename}")
     MATH(EXPR KAFKA_TEST_COUNT "${KAFKA_TEST_COUNT}+1")
     # The line below handles integration test
diff --git a/extensions/librdkafka/tests/CMakeLists.txt b/extensions/librdkafka/tests/CMakeLists.txt
index a258c1b..8c6193c 100644
--- a/extensions/librdkafka/tests/CMakeLists.txt
+++ b/extensions/librdkafka/tests/CMakeLists.txt
@@ -25,15 +25,15 @@ FOREACH(testfile ${KAFKA_TESTS})
     get_filename_component(testfilename "${testfile}" NAME_WE)
     add_executable("${testfilename}" "${testfile}")
     target_include_directories(${testfilename} PRIVATE BEFORE "${CMAKE_SOURCE_DIR}/extensions/librdkafka/")
-    target_wholearchive_library(${testfilename} minifi-rdkafka-extensions)
+    target_link_libraries(${testfilename} minifi-rdkafka-extensions)
     createTests("${testfilename}")
     MATH(EXPR KAFKA_TEST_COUNT "${KAFKA_TEST_COUNT}+1")
     target_include_directories(${testfilename} BEFORE PRIVATE "../..")
     target_include_directories(${testfilename} BEFORE PRIVATE "../../standard-processors/processors")
     target_include_directories(${testfilename} BEFORE PRIVATE "${CMAKE_SOURCE_DIR}/thirdparty/catch")
     target_include_directories(${testfilename} BEFORE PRIVATE "${CMAKE_SOURCE_DIR}/libminifi/test")
-    target_wholearchive_library(${testfilename} minifi-standard-processors)
-    target_wholearchive_library(${testfilename} minifi-expression-language-extensions)
+    target_link_libraries(${testfilename} minifi-standard-processors)
+    target_link_libraries(${testfilename} minifi-expression-language-extensions)
     target_link_libraries(${testfilename} ${CATCH_MAIN_LIB})
     add_test(NAME "${testfilename}" COMMAND "${testfilename}" "${TEST_RESOURCES}/TestKafkaOnSchedule.yml"  "${TEST_RESOURCES}/")
 ENDFOREACH()
diff --git a/extensions/mqtt/CMakeLists.txt b/extensions/mqtt/CMakeLists.txt
index 8483136..9daa15d 100644
--- a/extensions/mqtt/CMakeLists.txt
+++ b/extensions/mqtt/CMakeLists.txt
@@ -22,8 +22,7 @@ include_directories(./controllerservice ./processors ./protocol ../../libminifi/
 
 file(GLOB SOURCES "*.cpp" "protocol/*.cpp" "processors/*.cpp" "controllerservice/*.cpp")
 
-add_library(minifi-mqtt-extensions STATIC ${SOURCES})
-set_property(TARGET minifi-mqtt-extensions PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-mqtt-extensions SHARED ${SOURCES})
 
 target_link_libraries(minifi-mqtt-extensions ${LIBMINIFI})
 
diff --git a/extensions/mqtt/MQTTLoader.cpp b/extensions/mqtt/MQTTLoader.cpp
deleted file mode 100644
index 869d41f..0000000
--- a/extensions/mqtt/MQTTLoader.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "MQTTLoader.h"
-#include "core/FlowConfiguration.h"
-
-bool MQTTFactory::added = core::FlowConfiguration::add_static_func("createMQTTFactory");
-
-extern "C" {
-
-void *createMQTTFactory(void) {
-  return new MQTTFactory();
-}
-
-}
diff --git a/extensions/mqtt/MQTTLoader.h b/extensions/mqtt/MQTTLoader.h
deleted file mode 100644
index 95475c2..0000000
--- a/extensions/mqtt/MQTTLoader.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <vector>
-#include <string>
-#include <memory>
-
-#include "controllerservice/MQTTControllerService.h"
-#include "processors/PublishMQTT.h"
-#include "processors/ConsumeMQTT.h"
-#include "MQTTC2Protocol.h"
-#include "core/ClassLoader.h"
-#include "ConvertHeartBeat.h"
-#include "ConvertJSONAck.h"
-#include "ConvertUpdate.h"
-class MQTTFactory : public core::ObjectFactory {
- public:
-  MQTTFactory() = default;
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  virtual std::string getName() {
-    return "MQTTFactory";
-  }
-
-  virtual std::string getClassName() {
-    return "MQTTFactory";
-  }
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  virtual std::vector<std::string> getClassNames() {
-    std::vector<std::string> class_names;
-    class_names.push_back("PublishMQTT");
-    class_names.push_back("ConsumeMQTT");
-    class_names.push_back("MQTTContextService");
-    class_names.push_back("MQTTC2Protocol");
-    class_names.push_back("ConvertHeartBeat");
-    class_names.push_back("ConvertJSONAck");
-    class_names.push_back("ConvertUpdate");
-    return class_names;
-  }
-
-  virtual std::unique_ptr<ObjectFactory> assign(const std::string &class_name) {
-    if (utils::StringUtils::equalsIgnoreCase(class_name, "PublishMQTT")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::processors::PublishMQTT>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "ConsumeMQTT")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::processors::ConsumeMQTT>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "MQTTContextService")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::controllers::MQTTControllerService>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "MQTTC2Protocol")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::c2::MQTTC2Protocol>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "ConvertHeartBeat")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::processors::ConvertHeartBeat>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "ConvertJSONAck")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::processors::ConvertJSONAck>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "ConvertUpdate")) {
-          return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::processors::ConvertUpdate>());
-    } else {
-      return nullptr;
-    }
-  }
-
-  static bool added;
-};
-
-extern "C" {
-DLL_EXPORT void *createMQTTFactory(void);
-}
diff --git a/extensions/mqtt/controllerservice/MQTTControllerService.cpp b/extensions/mqtt/controllerservice/MQTTControllerService.cpp
index 7595e74..4a10266 100644
--- a/extensions/mqtt/controllerservice/MQTTControllerService.cpp
+++ b/extensions/mqtt/controllerservice/MQTTControllerService.cpp
@@ -24,6 +24,7 @@
 #include <memory>
 #include <set>
 #include "core/Property.h"
+#include "core/Resource.h"
 #include "io/validation.h"
 #include "properties/Configure.h"
 
@@ -92,6 +93,8 @@ void MQTTControllerService::initializeProperties() {
   setSupportedProperties(supportedProperties);
 }
 
+REGISTER_INTERNAL_RESOURCE_AS(MQTTControllerService, ("MQTTContextService"));
+
 } /* namespace controllers */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/mqtt/controllerservice/MQTTControllerService.h b/extensions/mqtt/controllerservice/MQTTControllerService.h
index 3c99e52..36abcae 100644
--- a/extensions/mqtt/controllerservice/MQTTControllerService.h
+++ b/extensions/mqtt/controllerservice/MQTTControllerService.h
@@ -26,7 +26,6 @@
 #include <map>
 #include <string>
 
-#include "core/Resource.h"
 #include "utils/StringUtils.h"
 #include "core/controller/ControllerService.h"
 #include "core/logging/LoggerConfiguration.h"
diff --git a/extensions/mqtt/processors/ConsumeMQTT.cpp b/extensions/mqtt/processors/ConsumeMQTT.cpp
index fdde744..ba60d2a 100644
--- a/extensions/mqtt/processors/ConsumeMQTT.cpp
+++ b/extensions/mqtt/processors/ConsumeMQTT.cpp
@@ -31,6 +31,7 @@
 #include "utils/StringUtils.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -109,6 +110,8 @@ void ConsumeMQTT::onTrigger(const std::shared_ptr<core::ProcessContext>& /*conte
   }
 }
 
+REGISTER_RESOURCE(ConsumeMQTT, "This Processor gets the contents of a FlowFile from a MQTT broker for a specified topic. The the payload of the MQTT message becomes content of a FlowFile");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/mqtt/processors/ConsumeMQTT.h b/extensions/mqtt/processors/ConsumeMQTT.h
index d279fc0..e39785b 100644
--- a/extensions/mqtt/processors/ConsumeMQTT.h
+++ b/extensions/mqtt/processors/ConsumeMQTT.h
@@ -28,7 +28,6 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Core.h"
-#include "core/Resource.h"
 #include "core/Property.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "concurrentqueue.h"
@@ -130,8 +129,6 @@ class ConsumeMQTT : public processors::AbstractMQTTProcessor {
   moodycamel::ConcurrentQueue<MQTTClient_message *> queue_;
 };
 
-REGISTER_RESOURCE(ConsumeMQTT, "This Processor gets the contents of a FlowFile from a MQTT broker for a specified topic. The the payload of the MQTT message becomes content of a FlowFile");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/mqtt/processors/ConvertBase.h b/extensions/mqtt/processors/ConvertBase.h
index 4b1bbbd..d994bfa 100644
--- a/extensions/mqtt/processors/ConvertBase.h
+++ b/extensions/mqtt/processors/ConvertBase.h
@@ -25,7 +25,6 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Core.h"
-#include "core/Resource.h"
 #include "core/Property.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "MQTTClient.h"
diff --git a/extensions/mqtt/processors/ConvertHeartBeat.cpp b/extensions/mqtt/processors/ConvertHeartBeat.cpp
index 5fcb95b..a7e36a3 100644
--- a/extensions/mqtt/processors/ConvertHeartBeat.cpp
+++ b/extensions/mqtt/processors/ConvertHeartBeat.cpp
@@ -27,6 +27,7 @@
 #include "utils/StringUtils.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 #include "ConvertHeartBeat.h"
 #include "c2/PayloadSerializer.h"
 #include "utils/ByteArrayCallback.h"
@@ -69,6 +70,8 @@ void ConvertHeartBeat::onTrigger(const std::shared_ptr<core::ProcessContext> &co
   }
 }
 
+REGISTER_INTERNAL_RESOURCE(ConvertHeartBeat);
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/mqtt/processors/ConvertHeartBeat.h b/extensions/mqtt/processors/ConvertHeartBeat.h
index 9f0292e..7c7d6a7 100644
--- a/extensions/mqtt/processors/ConvertHeartBeat.h
+++ b/extensions/mqtt/processors/ConvertHeartBeat.h
@@ -62,7 +62,6 @@ class ConvertHeartBeat: public ConvertBase{
   std::shared_ptr<logging::Logger> logger_;
 };
 
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/mqtt/processors/ConvertJSONAck.cpp b/extensions/mqtt/processors/ConvertJSONAck.cpp
index 57f6c9e..8355335 100644
--- a/extensions/mqtt/processors/ConvertJSONAck.cpp
+++ b/extensions/mqtt/processors/ConvertJSONAck.cpp
@@ -27,8 +27,10 @@
 #include "utils/StringUtils.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 #include "c2/PayloadSerializer.h"
 #include "utils/ByteArrayCallback.h"
+
 namespace org {
 namespace apache {
 namespace nifi {
@@ -104,6 +106,8 @@ void ConvertJSONAck::onTrigger(const std::shared_ptr<core::ProcessContext> &cont
   session->transfer(flow, Success);
 }
 
+REGISTER_INTERNAL_RESOURCE(ConvertJSONAck);
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/mqtt/processors/ConvertJSONAck.h b/extensions/mqtt/processors/ConvertJSONAck.h
index 8ec804e..7d27982 100644
--- a/extensions/mqtt/processors/ConvertJSONAck.h
+++ b/extensions/mqtt/processors/ConvertJSONAck.h
@@ -26,7 +26,6 @@
 #include "FlowFileRecord.h"
 #include "core/ProcessSession.h"
 #include "core/Core.h"
-#include "core/Resource.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "ConvertBase.h"
 #include "utils/gsl.h"
diff --git a/extensions/mqtt/processors/ConvertUpdate.cpp b/extensions/mqtt/processors/ConvertUpdate.cpp
index b759eef..2abf936 100644
--- a/extensions/mqtt/processors/ConvertUpdate.cpp
+++ b/extensions/mqtt/processors/ConvertUpdate.cpp
@@ -25,6 +25,7 @@
 #include "utils/HTTPClient.h"
 #include "io/BaseStream.h"
 #include "io/BufferStream.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -103,6 +104,8 @@ void ConvertUpdate::initialize() {
   setSupportedRelationships(relationships);
 }
 
+REGISTER_INTERNAL_RESOURCE(ConvertUpdate);
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/mqtt/processors/PublishMQTT.cpp b/extensions/mqtt/processors/PublishMQTT.cpp
index 4259f03..1a3686e 100644
--- a/extensions/mqtt/processors/PublishMQTT.cpp
+++ b/extensions/mqtt/processors/PublishMQTT.cpp
@@ -32,6 +32,7 @@
 #include "utils/StringUtils.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -99,6 +100,8 @@ void PublishMQTT::onTrigger(const std::shared_ptr<core::ProcessContext>& /*conte
   }
 }
 
+REGISTER_RESOURCE(PublishMQTT, "PublishMQTT serializes FlowFile content as an MQTT payload, sending the message to the configured topic and broker.");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/mqtt/processors/PublishMQTT.h b/extensions/mqtt/processors/PublishMQTT.h
index 710d597..925ac38 100644
--- a/extensions/mqtt/processors/PublishMQTT.h
+++ b/extensions/mqtt/processors/PublishMQTT.h
@@ -29,7 +29,6 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Core.h"
-#include "core/Resource.h"
 #include "core/Property.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "MQTTClient.h"
@@ -147,8 +146,6 @@ class PublishMQTT : public processors::AbstractMQTTProcessor {
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(PublishMQTT, "PublishMQTT serializes FlowFile content as an MQTT payload, sending the message to the configured topic and broker.");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/mqtt/protocol/MQTTC2Protocol.cpp b/extensions/mqtt/protocol/MQTTC2Protocol.cpp
index 7b0da5b..f63c8f9 100644
--- a/extensions/mqtt/protocol/MQTTC2Protocol.cpp
+++ b/extensions/mqtt/protocol/MQTTC2Protocol.cpp
@@ -16,6 +16,7 @@
  * limitations under the License.
  */
 #include "MQTTC2Protocol.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -96,6 +97,8 @@ C2Payload MQTTC2Protocol::serialize(const C2Payload &payload) {
   return C2Payload(payload.getOperation(), state::UpdateState::READ_ERROR);
 }
 
+REGISTER_INTERNAL_RESOURCE(MQTTC2Protocol);
+
 } /* namespace c2 */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/mqtt/protocol/MQTTC2Protocol.h b/extensions/mqtt/protocol/MQTTC2Protocol.h
index 0c9ff77..da5c2f9 100644
--- a/extensions/mqtt/protocol/MQTTC2Protocol.h
+++ b/extensions/mqtt/protocol/MQTTC2Protocol.h
@@ -84,6 +84,7 @@ class MQTTC2Protocol : public C2Protocol {
   // mqtt controller serviec name.
   std::string controller_service_name_;
 };
+
 } /* namespace c2 */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/opc/CMakeLists.txt b/extensions/opc/CMakeLists.txt
index a029143..b931d12 100644
--- a/extensions/opc/CMakeLists.txt
+++ b/extensions/opc/CMakeLists.txt
@@ -25,8 +25,7 @@ include_directories(include)
 
 file(GLOB SOURCES "src/*.cpp")
 
-add_library(minifi-opc-extensions STATIC ${SOURCES})
-set_property(TARGET minifi-opc-extensions PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-opc-extensions SHARED ${SOURCES})
 
 target_link_libraries(minifi-opc-extensions ${LIBMINIFI} Threads::Threads)
 target_link_libraries(minifi-opc-extensions ${CMAKE_DL_LIBS} spdlog open62541::open62541)
diff --git a/extensions/opc/include/fetchopc.h b/extensions/opc/include/fetchopc.h
index 8e210cb..ed391a3 100644
--- a/extensions/opc/include/fetchopc.h
+++ b/extensions/opc/include/fetchopc.h
@@ -30,7 +30,6 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Property.h"
-#include "core/Resource.h"
 #include "controllers/SSLContextService.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "utils/Id.h"
@@ -98,8 +97,6 @@ class FetchOPCProcessor : public BaseOPCProcessor {
   std::unordered_map<std::string, std::string> node_timestamp_;  // Key = Full path, Value = Timestamp
 };
 
-REGISTER_RESOURCE(FetchOPCProcessor, "Fetches OPC-UA node");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/opc/include/putopc.h b/extensions/opc/include/putopc.h
index 7443361..0497693 100644
--- a/extensions/opc/include/putopc.h
+++ b/extensions/opc/include/putopc.h
@@ -30,7 +30,6 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Property.h"
-#include "core/Resource.h"
 #include "controllers/SSLContextService.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "utils/Id.h"
@@ -94,8 +93,6 @@ class PutOPCProcessor : public BaseOPCProcessor {
   opc::OPCNodeDataType nodeDataType_;
 };
 
-REGISTER_RESOURCE(PutOPCProcessor, "Creates/updates  OPC nodes");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/opc/src/fetchopc.cpp b/extensions/opc/src/fetchopc.cpp
index 3778215..cfb8c5d 100644
--- a/extensions/opc/src/fetchopc.cpp
+++ b/extensions/opc/src/fetchopc.cpp
@@ -238,6 +238,8 @@ namespace processors {
     session->transfer(flowFile, Success);
   }
 
+REGISTER_RESOURCE(FetchOPCProcessor, "Fetches OPC-UA node");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/opc/src/putopc.cpp b/extensions/opc/src/putopc.cpp
index d0a7e0a..5936ce3 100644
--- a/extensions/opc/src/putopc.cpp
+++ b/extensions/opc/src/putopc.cpp
@@ -440,6 +440,8 @@ namespace processors {
     return gsl::narrow<int64_t>(size);
   }
 
+REGISTER_RESOURCE(PutOPCProcessor, "Creates/updates  OPC nodes");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/opencv/CMakeLists.txt b/extensions/opencv/CMakeLists.txt
index 8ba97d3..3888beb 100644
--- a/extensions/opencv/CMakeLists.txt
+++ b/extensions/opencv/CMakeLists.txt
@@ -21,7 +21,7 @@ include(${CMAKE_SOURCE_DIR}/extensions/ExtensionHeader.txt)
 
 file(GLOB SOURCES  "*.cpp")
 
-add_library(minifi-opencv STATIC ${SOURCES})
+add_library(minifi-opencv SHARED ${SOURCES})
 
 target_link_libraries(minifi-opencv ${LIBMINIFI})
 target_link_libraries(minifi-opencv OPENCV::libopencv)
diff --git a/extensions/opencv/CaptureRTSPFrame.cpp b/extensions/opencv/CaptureRTSPFrame.cpp
index dc241ba..ca4b676 100644
--- a/extensions/opencv/CaptureRTSPFrame.cpp
+++ b/extensions/opencv/CaptureRTSPFrame.cpp
@@ -17,6 +17,7 @@
 #include <set>
 
 #include "CaptureRTSPFrame.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -174,6 +175,8 @@ void CaptureRTSPFrame::onTrigger(const std::shared_ptr<core::ProcessContext> &co
 void CaptureRTSPFrame::notifyStop() {
 }
 
+REGISTER_RESOURCE(CaptureRTSPFrame, "Captures a frame from the RTSP stream at specified intervals."); // NOLINT
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/opencv/CaptureRTSPFrame.h b/extensions/opencv/CaptureRTSPFrame.h
index 3c16743..ddac409 100644
--- a/extensions/opencv/CaptureRTSPFrame.h
+++ b/extensions/opencv/CaptureRTSPFrame.h
@@ -26,9 +26,9 @@
 #include <string>
 #include <opencv2/opencv.hpp>
 
-#include "core/Resource.h"
 #include "core/Processor.h"
 #include "utils/gsl.h"
+#include "utils/Export.h"
 
 
 namespace org {
@@ -44,15 +44,15 @@ class CaptureRTSPFrame : public core::Processor {
         logger_(logging::LoggerFactory<CaptureRTSPFrame>::getLogger()) {
   }
 
-  static core::Property RTSPUsername;
-  static core::Property RTSPPassword;
-  static core::Property RTSPHostname;
-  static core::Property RTSPURI;
-  static core::Property RTSPPort;
-  static core::Property ImageEncoding;
+  EXTENSIONAPI static core::Property RTSPUsername;
+  EXTENSIONAPI static core::Property RTSPPassword;
+  EXTENSIONAPI static core::Property RTSPHostname;
+  EXTENSIONAPI static core::Property RTSPURI;
+  EXTENSIONAPI static core::Property RTSPPort;
+  EXTENSIONAPI static core::Property ImageEncoding;
 
-  static core::Relationship Success;
-  static core::Relationship Failure;
+  EXTENSIONAPI static core::Relationship Success;
+  EXTENSIONAPI static core::Relationship Failure;
 
   void initialize() override;
   void onSchedule(core::ProcessContext *context, core::ProcessSessionFactory *sessionFactory) override;
@@ -131,8 +131,6 @@ class CaptureRTSPFrame : public core::Processor {
 //  std::shared_ptr<minifi::controllers::SSLContextService> ssl_service_;
 };
 
-REGISTER_RESOURCE(CaptureRTSPFrame, "Captures a frame from the RTSP stream at specified intervals."); // NOLINT
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/opencv/MotionDetector.cpp b/extensions/opencv/MotionDetector.cpp
index d67b47a..201a40e 100644
--- a/extensions/opencv/MotionDetector.cpp
+++ b/extensions/opencv/MotionDetector.cpp
@@ -21,6 +21,7 @@
 
 #include "MotionDetector.h"
 #include "FrameIO.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -201,6 +202,8 @@ void MotionDetector::onTrigger(const std::shared_ptr<core::ProcessContext> &cont
 void MotionDetector::notifyStop() {
 }
 
+REGISTER_RESOURCE(MotionDetector, "Detect motion from captured images.");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/opencv/MotionDetector.h b/extensions/opencv/MotionDetector.h
index 95a7404..e511be0 100644
--- a/extensions/opencv/MotionDetector.h
+++ b/extensions/opencv/MotionDetector.h
@@ -21,7 +21,6 @@
 #include <memory>
 #include <string>
 
-#include "core/Resource.h"
 #include "core/Processor.h"
 #include "opencv2/opencv.hpp"
 #include "opencv2/imgproc.hpp"
@@ -70,8 +69,6 @@ class MotionDetector : public core::Processor {
   const double IMG_WIDTH = 500.0;
 };
 
-REGISTER_RESOURCE(MotionDetector, "Detect motion from captured images.");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/opencv/OpenCVLoader.cpp b/extensions/opencv/OpenCVLoader.cpp
index eb7cfba..48a1e26 100644
--- a/extensions/opencv/OpenCVLoader.cpp
+++ b/extensions/opencv/OpenCVLoader.cpp
@@ -15,17 +15,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include "OpenCVLoader.h"
+#include "core/extension/Extension.h"
+#include "utils/Environment.h"
 
-#include "core/FlowConfiguration.h"
-
-bool OpenCVObjectFactory::added = core::FlowConfiguration::add_static_func("createOpenCVFactory");
-extern "C" {
-
-
-
-void *createOpenCVFactory(void) {
-  return new OpenCVObjectFactory();
+static bool init(const std::shared_ptr<org::apache::nifi::minifi::Configure>& /*config*/) {
+  // By default in OpenCV, ffmpeg capture is hardcoded to use TCP and this is a workaround
+  // also if UDP timeout, ffmpeg will retry with TCP
+  // Note:
+  // 1. OpenCV community are trying to find a better approach than setenv.
+  // 2. The command will not overwrite value if "OPENCV_FFMPEG_CAPTURE_OPTIONS" already exists.
+  return org::apache::nifi::minifi::utils::Environment::setEnvironmentVariable("OPENCV_FFMPEG_CAPTURE_OPTIONS", "rtsp_transport;udp", false /*overwrite*/);
 }
 
-}
+static void deinit() {}
+
+REGISTER_EXTENSION("OpenCVExtension", init, deinit);
diff --git a/extensions/opencv/OpenCVLoader.h b/extensions/opencv/OpenCVLoader.h
deleted file mode 100644
index 84ae4a3..0000000
--- a/extensions/opencv/OpenCVLoader.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <vector>
-#include <string>
-#include <memory>
-
-#include "CaptureRTSPFrame.h"
-#include "core/ClassLoader.h"
-#include "utils/Environment.h"
-
-class OpenCVObjectFactoryInitializer : public core::ObjectFactoryInitializer {
- public:
-  virtual bool initialize() {
-    // By default in OpenCV, ffmpeg capture is hardcoded to use TCP and this is a workaround
-    // also if UDP timeout, ffmpeg will retry with TCP
-    // Note:
-    // 1. OpenCV community are trying to find a better approach than setenv.
-    // 2. The command will not overwrite value if "OPENCV_FFMPEG_CAPTURE_OPTIONS" already exists.
-    return utils::Environment::setEnvironmentVariable("OPENCV_FFMPEG_CAPTURE_OPTIONS", "rtsp_transport;udp", false /*overwrite*/);
-  }
-
-  virtual void deinitialize() {
-  }
-};
-
-class OpenCVObjectFactory : public core::ObjectFactory {
- public:
-  OpenCVObjectFactory() = default;
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  std::string getName() override {
-    return "OpenCVObjectFactory";
-  }
-
-  std::string getClassName() override {
-    return "OpenCVObjectFactory";
-  }
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  std::vector<std::string> getClassNames() override {
-    std::vector<std::string> class_names;
-    class_names.push_back("CaptureRTSPFrame");
-    return class_names;
-  }
-
-  std::unique_ptr<ObjectFactory> assign(const std::string &class_name) override {
-    if (utils::StringUtils::equalsIgnoreCase(class_name, "CaptureRTSPFrame")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::processors::CaptureRTSPFrame>());
-    } else {
-      return nullptr;
-    }
-  }
-
-  std::unique_ptr<core::ObjectFactoryInitializer> getInitializer() override {
-    return std::unique_ptr<core::ObjectFactoryInitializer>(new OpenCVObjectFactoryInitializer());
-  }
-
-  static bool added;
-};
-
-extern "C" {
-  DLL_EXPORT void *createOpenCVFactory(void);
-}
diff --git a/extensions/opencv/tests/CMakeLists.txt b/extensions/opencv/tests/CMakeLists.txt
index d0e1b03..f26b21e 100644
--- a/extensions/opencv/tests/CMakeLists.txt
+++ b/extensions/opencv/tests/CMakeLists.txt
@@ -26,8 +26,8 @@ FOREACH(testfile ${OPENCV_TESTS})
 	add_executable("${testfilename}" "${testfile}")
 	target_include_directories(${testfilename} PRIVATE BEFORE "${CMAKE_SOURCE_DIR}/extensions/opencv/")
 	target_include_directories(${testfilename} PRIVATE BEFORE "${CMAKE_SOURCE_DIR}/extensions/standard-processors")
-	target_wholearchive_library(${testfilename} minifi-opencv)
-	target_wholearchive_library(${testfilename} minifi-standard-processors)
+	target_link_libraries(${testfilename} minifi-opencv)
+	target_link_libraries(${testfilename} minifi-standard-processors)
 	createTests("${testfilename}")
 	MATH(EXPR OPENCV_TEST_COUNT "${OPENCV_TEST_COUNT}+1")
 	add_test(NAME "${testfilename}" COMMAND "${testfilename}" WORKING_DIRECTORY ${TEST_DIR})
diff --git a/extensions/openwsman/CMakeLists.txt b/extensions/openwsman/CMakeLists.txt
index 0903ba1..02a8604 100644
--- a/extensions/openwsman/CMakeLists.txt
+++ b/extensions/openwsman/CMakeLists.txt
@@ -21,9 +21,7 @@ include(${CMAKE_SOURCE_DIR}/extensions/ExtensionHeader.txt)
 
 file(GLOB SOURCES "processors/*.cpp")
 
-add_library(minifi-openwsman STATIC ${SOURCES})
-
-set_property(TARGET minifi-openwsman PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-openwsman SHARED ${SOURCES})
 
 target_link_libraries(minifi-openwsman ${LIBMINIFI} Threads::Threads)
 target_link_libraries(minifi-openwsman OpenWSMAN::libwsman CIVETWEB::civetweb-cpp CIVETWEB::c-library LibXml2::LibXml2)
diff --git a/extensions/openwsman/processors/SourceInitiatedSubscriptionListener.cpp b/extensions/openwsman/processors/SourceInitiatedSubscriptionListener.cpp
index ee93d01..13e25ce 100644
--- a/extensions/openwsman/processors/SourceInitiatedSubscriptionListener.cpp
+++ b/extensions/openwsman/processors/SourceInitiatedSubscriptionListener.cpp
@@ -48,6 +48,7 @@ extern "C" {
 #include "core/logging/Logger.h"
 #include "core/ProcessContext.h"
 #include "core/Relationship.h"
+#include "core/Resource.h"
 #include "io/BufferStream.h"
 #include "io/StreamFactory.h"
 #include "ResourceClaim.h"
@@ -916,6 +917,9 @@ void SourceInitiatedSubscriptionListener::notifyStop() {
   server_.release();
 }
 
+REGISTER_RESOURCE(SourceInitiatedSubscriptionListener, "This processor implements a Windows Event Forwarding Source Initiated Subscription server with the help of OpenWSMAN. "
+                                                       "Windows hosts can be set up to connect and forward Event Logs to this processor.");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/openwsman/processors/SourceInitiatedSubscriptionListener.h b/extensions/openwsman/processors/SourceInitiatedSubscriptionListener.h
index 8f1c57e..e9f58d1 100644
--- a/extensions/openwsman/processors/SourceInitiatedSubscriptionListener.h
+++ b/extensions/openwsman/processors/SourceInitiatedSubscriptionListener.h
@@ -35,7 +35,6 @@ extern "C" {
 #include "core/ProcessSession.h"
 #include "core/Core.h"
 #include "core/Property.h"
-#include "core/Resource.h"
 #include "controllers/SSLContextService.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "utils/Id.h"
@@ -160,9 +159,6 @@ class SourceInitiatedSubscriptionListener : public core::Processor {
   bool loadState();
 };
 
-REGISTER_RESOURCE(SourceInitiatedSubscriptionListener, "This processor implements a Windows Event Forwarding Source Initiated Subscription server with the help of OpenWSMAN. "
-                                                       "Windows hosts can be set up to connect and forward Event Logs to this processor.");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/pcap/CMakeLists.txt b/extensions/pcap/CMakeLists.txt
index 2d9f58b..509eda6 100644
--- a/extensions/pcap/CMakeLists.txt
+++ b/extensions/pcap/CMakeLists.txt
@@ -51,8 +51,7 @@ set(PCAPPLUSPLUS_LIB_DIR "${PCAPPLUSPLUS_BASE_DIR}/Dist")
 
 file(GLOB SOURCES  "*.cpp")
 
-add_library(minifi-pcap STATIC ${SOURCES})
-set_property(TARGET minifi-pcap PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-pcap SHARED ${SOURCES})
 
 add_dependencies(minifi-pcap pcappp)
 
diff --git a/extensions/pcap/CapturePacket.cpp b/extensions/pcap/CapturePacket.cpp
index 33cf5d1..0882332 100644
--- a/extensions/pcap/CapturePacket.cpp
+++ b/extensions/pcap/CapturePacket.cpp
@@ -39,6 +39,7 @@
 #include "core/logging/Logger.h"
 #include "core/ProcessContext.h"
 #include "core/Relationship.h"
+#include "core/Resource.h"
 #include "CapturePacket.h"
 #include "ResourceClaim.h"
 #include "utils/StringUtils.h"
@@ -230,6 +231,10 @@ void CapturePacket::onTrigger(const std::shared_ptr<core::ProcessContext> &conte
   }
 }
 
+REGISTER_RESOURCE(CapturePacket, "CapturePacket captures and writes one or more packets into a PCAP file that will be used as the content of a flow file."
+    " Configuration options exist to adjust the batching of PCAP files. PCAP batching will place a single PCAP into a flow file. "
+    "A regular expression selects network interfaces. Bluetooth network interfaces can be selected through a separate option.");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/pcap/CapturePacket.h b/extensions/pcap/CapturePacket.h
index c6ce10c..c59f82c 100644
--- a/extensions/pcap/CapturePacket.h
+++ b/extensions/pcap/CapturePacket.h
@@ -31,7 +31,6 @@
 #include "core/ProcessSession.h"
 #include "core/Core.h"
 #include "core/Property.h"
-#include "core/Resource.h"
 #include "concurrentqueue.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "utils/Id.h"
@@ -164,10 +163,6 @@ class CapturePacket : public core::Processor {
   static std::shared_ptr<utils::IdGenerator> id_generator_;
 };
 
-REGISTER_RESOURCE(CapturePacket, "CapturePacket captures and writes one or more packets into a PCAP file that will be used as the content of a flow file."
-    " Configuration options exist to adjust the batching of PCAP files. PCAP batching will place a single PCAP into a flow file. "
-    "A regular expression selects network interfaces. Bluetooth network interfaces can be selected through a separate option.");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/pcap/PcapLoader.cpp b/extensions/pcap/PcapLoader.cpp
deleted file mode 100644
index c26b80c..0000000
--- a/extensions/pcap/PcapLoader.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "core/FlowConfiguration.h"
-#include "PcapLoader.h"
-
-bool PcapFactory::added = core::FlowConfiguration::add_static_func("createPcapFactory");
-
-extern "C" {
-
-void *createPcapFactory(void) {
-  return new PcapFactory();
-}
-
-}
diff --git a/extensions/pcap/PcapLoader.h b/extensions/pcap/PcapLoader.h
deleted file mode 100644
index 5b7c47d..0000000
--- a/extensions/pcap/PcapLoader.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <vector>
-#include <string>
-#include <memory>
-
-#include "core/ClassLoader.h"
-#include "CapturePacket.h"
-#include "utils/StringUtils.h"
-
-class PcapFactory : public core::ObjectFactory {
- public:
-  PcapFactory() = default;
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  virtual std::string getName() {
-    return "PcapFactory";
-  }
-
-  virtual std::string getClassName() {
-    return "PcapFactory";
-  }
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  virtual std::vector<std::string> getClassNames() {
-    std::vector<std::string> class_names;
-    class_names.push_back("CapturePacket");
-    return class_names;
-  }
-
-  virtual std::unique_ptr<ObjectFactory> assign(const std::string &class_name) {
-    if (utils::StringUtils::equalsIgnoreCase(class_name, "CapturePacket")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<processors::CapturePacket>());
-    } else {
-      return nullptr;
-    }
-  }
-
-  static bool added;
-};
-
-extern "C" {
-DLL_EXPORT void *createPcapFactory(void);
-}
diff --git a/extensions/pdh/CMakeLists.txt b/extensions/pdh/CMakeLists.txt
index d6c644e..94bdcbf 100644
--- a/extensions/pdh/CMakeLists.txt
+++ b/extensions/pdh/CMakeLists.txt
@@ -21,8 +21,7 @@ include(${CMAKE_SOURCE_DIR}/extensions/ExtensionHeader.txt)
 
 file(GLOB SOURCES  "*.cpp")
 
-add_library(minifi-pdh STATIC ${SOURCES})
-set_property(TARGET minifi-pdh PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-pdh SHARED ${SOURCES})
 
 target_link_libraries(minifi-pdh ${LIBMINIFI} pdh)
 
diff --git a/extensions/pdh/PerformanceDataMonitor.cpp b/extensions/pdh/PerformanceDataMonitor.cpp
index d449cae..b317ec4 100644
--- a/extensions/pdh/PerformanceDataMonitor.cpp
+++ b/extensions/pdh/PerformanceDataMonitor.cpp
@@ -26,6 +26,7 @@
 #include "utils/StringUtils.h"
 #include "utils/JsonCallback.h"
 #include "utils/OpenTelemetryLogDataModelUtils.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -336,6 +337,8 @@ void PerformanceDataMonitor::setupMembersFromProperties(const std::shared_ptr<co
   setupDecimalPlacesFromProperties(context);
 }
 
+REGISTER_RESOURCE(PerformanceDataMonitor, "This processor can create FlowFiles with various performance data through Performance Data Helper. (Windows only)");
+
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/pdh/PerformanceDataMonitor.h b/extensions/pdh/PerformanceDataMonitor.h
index 363b446..3539741 100644
--- a/extensions/pdh/PerformanceDataMonitor.h
+++ b/extensions/pdh/PerformanceDataMonitor.h
@@ -54,13 +54,13 @@ class PerformanceDataMonitor : public core::Processor {
   ~PerformanceDataMonitor() override;
   static constexpr char const* ProcessorName = "PerformanceDataMonitor";
   // Supported Properties
-  static core::Property PredefinedGroups;
-  static core::Property CustomPDHCounters;
-  static core::Property OutputFormatProperty;
-  static core::Property OutputCompactness;
-  static core::Property DecimalPlaces;
+  EXTENSIONAPI static core::Property PredefinedGroups;
+  EXTENSIONAPI static core::Property CustomPDHCounters;
+  EXTENSIONAPI static core::Property OutputFormatProperty;
+  EXTENSIONAPI static core::Property OutputCompactness;
+  EXTENSIONAPI static core::Property DecimalPlaces;
   // Supported Relationships
-  static core::Relationship Success;
+  EXTENSIONAPI static core::Relationship Success;
 
 
  public:
@@ -92,8 +92,6 @@ class PerformanceDataMonitor : public core::Processor {
   std::vector<std::unique_ptr<PerformanceDataCounter>> resource_consumption_counters_;
 };
 
-REGISTER_RESOURCE(PerformanceDataMonitor, "This processor can create FlowFiles with various performance data through Performance Data Helper. (Windows only)");
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/pdh/tests/CMakeLists.txt b/extensions/pdh/tests/CMakeLists.txt
index 29d144b..6e7153c 100644
--- a/extensions/pdh/tests/CMakeLists.txt
+++ b/extensions/pdh/tests/CMakeLists.txt
@@ -29,8 +29,8 @@ FOREACH(testfile ${PDH_TESTS})
 	target_include_directories(${testfilename} PRIVATE BEFORE "${CMAKE_SOURCE_DIR}/extensions/standard-processors")
 	createTests("${testfilename}")
 	target_link_libraries(${testfilename} ${CATCH_MAIN_LIB})
-	target_wholearchive_library(${testfilename} minifi-pdh)
-	target_wholearchive_library(${testfilename} minifi-standard-processors)
+	target_link_libraries(${testfilename} minifi-pdh)
+	target_link_libraries(${testfilename} minifi-standard-processors)
 	MATH(EXPR PDH_TEST_COUNT "${PDH_TEST_COUNT}+1")
 	add_test(NAME "${testfilename}" COMMAND "${testfilename}" WORKING_DIRECTORY ${TEST_DIR})
 ENDFOREACH()
diff --git a/extensions/rocksdb-repos/CMakeLists.txt b/extensions/rocksdb-repos/CMakeLists.txt
index ee5ce4a..0f842f0 100644
--- a/extensions/rocksdb-repos/CMakeLists.txt
+++ b/extensions/rocksdb-repos/CMakeLists.txt
@@ -21,8 +21,7 @@ include(${CMAKE_SOURCE_DIR}/extensions/ExtensionHeader.txt)
 
 file(GLOB SOURCES  "*.cpp" "controllers/*.cpp" "database/*.cpp" "encryption/*.cpp")
 
-add_library(minifi-rocksdb-repos STATIC ${SOURCES})
-set_property(TARGET minifi-rocksdb-repos PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-rocksdb-repos SHARED ${SOURCES})
 
 target_link_libraries(minifi-rocksdb-repos ${LIBMINIFI} Threads::Threads)
 target_link_libraries(minifi-rocksdb-repos RocksDB::RocksDB)
diff --git a/extensions/rocksdb-repos/DatabaseContentRepository.cpp b/extensions/rocksdb-repos/DatabaseContentRepository.cpp
index 0eacce8..53e8d6e 100644
--- a/extensions/rocksdb-repos/DatabaseContentRepository.cpp
+++ b/extensions/rocksdb-repos/DatabaseContentRepository.cpp
@@ -27,6 +27,7 @@
 #include "utils/gsl.h"
 #include "Exception.h"
 #include "database/StringAppender.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -182,6 +183,8 @@ std::shared_ptr<io::BaseStream> DatabaseContentRepository::write(const minifi::R
   return std::make_shared<io::RocksDbStream>(claim.getContentFullPath(), gsl::make_not_null<minifi::internal::RocksDatabase*>(db_.get()), true, batch);
 }
 
+REGISTER_INTERNAL_RESOURCE_AS(DatabaseContentRepository, ("DatabaseContentRepository", "databasecontentrepository"));
+
 } /* namespace repository */
 } /* namespace core */
 } /* namespace minifi */
diff --git a/extensions/rocksdb-repos/FlowFileRepository.cpp b/extensions/rocksdb-repos/FlowFileRepository.cpp
index 3a60898..92cbef7 100644
--- a/extensions/rocksdb-repos/FlowFileRepository.cpp
+++ b/extensions/rocksdb-repos/FlowFileRepository.cpp
@@ -30,6 +30,7 @@
 #include "rocksdb/slice.h"
 #include "FlowFileRecord.h"
 #include "utils/gsl.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -259,6 +260,8 @@ void FlowFileRepository::loadComponent(const std::shared_ptr<core::ContentReposi
   initialize_repository();
 }
 
+REGISTER_INTERNAL_RESOURCE_AS(FlowFileRepository, ("FlowFileRepository", "flowfilerepository"));
+
 } /* namespace repository */
 } /* namespace core */
 } /* namespace minifi */
diff --git a/extensions/rocksdb-repos/ProvenanceRepository.cpp b/extensions/rocksdb-repos/ProvenanceRepository.cpp
index 6cdb0c5..962f31e 100644
--- a/extensions/rocksdb-repos/ProvenanceRepository.cpp
+++ b/extensions/rocksdb-repos/ProvenanceRepository.cpp
@@ -17,7 +17,11 @@
  */
 
 #include "ProvenanceRepository.h"
+
 #include <string>
+
+#include "core/Resource.h"
+
 namespace org {
 namespace apache {
 namespace nifi {
@@ -50,6 +54,9 @@ void ProvenanceRepository::run() {
     }
   }
 }
+
+REGISTER_INTERNAL_RESOURCE_AS(ProvenanceRepository, ("ProvenanceRepository", "provenancerepository"));
+
 } /* namespace provenance */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/rocksdb-repos/ProvenanceRepository.h b/extensions/rocksdb-repos/ProvenanceRepository.h
index 3134c74..745f082 100644
--- a/extensions/rocksdb-repos/ProvenanceRepository.h
+++ b/extensions/rocksdb-repos/ProvenanceRepository.h
@@ -29,6 +29,7 @@
 #include "core/Core.h"
 #include "provenance/Provenance.h"
 #include "core/logging/LoggerConfiguration.h"
+
 namespace org {
 namespace apache {
 namespace nifi {
diff --git a/extensions/rocksdb-repos/RocksDBLoader.cpp b/extensions/rocksdb-repos/RocksDBLoader.cpp
deleted file mode 100644
index 444c1db..0000000
--- a/extensions/rocksdb-repos/RocksDBLoader.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "core/FlowConfiguration.h"
-#include "RocksDBLoader.h"
-
-bool RocksDBFactory::added = core::FlowConfiguration::add_static_func("createRocksDBFactory");
-
-extern "C" {
-
-void *createRocksDBFactory(void) {
-  return new RocksDBFactory();
-}
-
-}
diff --git a/extensions/rocksdb-repos/RocksDBLoader.h b/extensions/rocksdb-repos/RocksDBLoader.h
deleted file mode 100644
index a441cac..0000000
--- a/extensions/rocksdb-repos/RocksDBLoader.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <vector>
-#include <string>
-#include <algorithm>
-#include <memory>
-
-#include "DatabaseContentRepository.h"
-#include "FlowFileRepository.h"
-#include "ProvenanceRepository.h"
-#include "RocksDbStream.h"
-#include "controllers/RocksDbPersistableKeyValueStoreService.h"
-#include "core/ClassLoader.h"
-
-class RocksDBFactory : public core::ObjectFactory {
- public:
-  RocksDBFactory() = default;
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  virtual std::string getName() {
-    return "RocksDBFactory";
-  }
-
-  virtual std::string getClassName() {
-    return "RocksDBFactory";
-  }
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  virtual std::vector<std::string> getClassNames() {
-    std::vector<std::string> class_names;
-    class_names.push_back("DatabaseContentRepository");
-    class_names.push_back("FlowFileRepository");
-    class_names.push_back("ProvenanceRepository");
-    class_names.push_back("RocksDbPersistableKeyValueStoreService");
-    class_names.push_back("databasecontentrepository");
-    class_names.push_back("flowfilerepository");
-    class_names.push_back("provenancerepository");
-    class_names.push_back("rocksdbpersistablekeyvaluestoreservice");
-    return class_names;
-  }
-
-  virtual std::unique_ptr<ObjectFactory> assign(const std::string &class_name) {
-    std::string name = class_name;
-    std::transform(name.begin(), name.end(), name.begin(), ::tolower);
-    if (name == "databasecontentrepository") {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<core::repository::DatabaseContentRepository>());
-    } else if (name == "flowfilerepository") {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<core::repository::FlowFileRepository>());
-    } else if (name == "provenancerepository") {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::provenance::ProvenanceRepository>());
-    } else if (name == "rocksdbpersistablekeyvaluestoreservice") {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::controllers::RocksDbPersistableKeyValueStoreService>());
-    } else {
-      return nullptr;
-    }
-  }
-
-  static bool added;
-};
-
-extern "C" {
-DLL_EXPORT void *createRocksDBFactory(void);
-}
diff --git a/extensions/rocksdb-repos/controllers/RocksDbPersistableKeyValueStoreService.cpp b/extensions/rocksdb-repos/controllers/RocksDbPersistableKeyValueStoreService.cpp
index 9b2dfa9..46322a9 100644
--- a/extensions/rocksdb-repos/controllers/RocksDbPersistableKeyValueStoreService.cpp
+++ b/extensions/rocksdb-repos/controllers/RocksDbPersistableKeyValueStoreService.cpp
@@ -21,6 +21,7 @@
 #include "RocksDbPersistableKeyValueStoreService.h"
 #include "../encryption/RocksDbEncryptionProvider.h"
 #include "utils/StringUtils.h"
+#include "core/Resource.h"
 
 
 namespace org {
@@ -217,6 +218,9 @@ bool RocksDbPersistableKeyValueStoreService::persist() {
   return opendb->FlushWAL(true /*sync*/).ok();
 }
 
+REGISTER_RESOURCE_AS(RocksDbPersistableKeyValueStoreService, "A key-value service implemented by RocksDB",
+                     ("RocksDbPersistableKeyValueStoreService", "rocksdbpersistablekeyvaluestoreservice"));
+
 } /* namespace controllers */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/rocksdb-repos/controllers/RocksDbPersistableKeyValueStoreService.h b/extensions/rocksdb-repos/controllers/RocksDbPersistableKeyValueStoreService.h
index bba7765..d48beac 100644
--- a/extensions/rocksdb-repos/controllers/RocksDbPersistableKeyValueStoreService.h
+++ b/extensions/rocksdb-repos/controllers/RocksDbPersistableKeyValueStoreService.h
@@ -74,8 +74,6 @@ class RocksDbPersistableKeyValueStoreService : public AbstractAutoPersistingKeyV
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(RocksDbPersistableKeyValueStoreService, "A key-value service implemented by RocksDB");
-
 } /* namespace controllers */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/script/CMakeLists.txt b/extensions/script/CMakeLists.txt
index 9fc24fa..bc35066 100644
--- a/extensions/script/CMakeLists.txt
+++ b/extensions/script/CMakeLists.txt
@@ -19,15 +19,9 @@
 
 include(${CMAKE_SOURCE_DIR}/extensions/ExtensionHeader.txt)
 
-set (OTHER_SOURCES "")
-if (NOT DISABLE_PYTHON_SCRIPTING)
-  set (OTHER_SOURCES "pythonloader/PyProcLoader.cpp")
-endif()
-
-file(GLOB SOURCES  "ExecuteScript.cpp" "ScriptFlowFile.cpp" "ScriptProcessContext.cpp" "${OTHER_SOURCES}")
+file(GLOB SOURCES  "ExecuteScript.cpp" "ScriptFlowFile.cpp" "ScriptProcessContext.cpp")
 
-add_library(minifi-script-extensions STATIC ${SOURCES})
-set_property(TARGET minifi-script-extensions PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-script-extensions SHARED ${SOURCES})
 
 target_link_libraries(minifi-script-extensions ${LIBMINIFI} Threads::Threads)
 
@@ -40,15 +34,11 @@ if (NOT DISABLE_PYTHON_SCRIPTING)
     include(Pybind11)
     add_definitions(-DPYTHON_SUPPORT)
 
-    file(GLOB PY_SOURCES  "python/*.cpp")
-    add_library(minifi-python-extensions STATIC ${PY_SOURCES})
-    target_include_directories(minifi-python-extensions SYSTEM PRIVATE ${PYTHON_INCLUDE_DIR})
-    target_include_directories(minifi-python-extensions SYSTEM PRIVATE ../../thirdparty/pybind11/include)
-    target_include_directories(minifi-python-extensions PRIVATE python)
-    target_link_libraries(minifi-python-extensions ${LIBMINIFI})
-    target_link_libraries(minifi-python-extensions ${PYTHON_LIBRARIES})
-    target_link_libraries(minifi-python-extensions pybind11)
-    target_link_libraries(minifi-script-extensions minifi-python-extensions)
+    file(GLOB PY_SOURCES  "python/*.cpp" "pythonloader/PyProcLoader.cpp")
+    target_sources(minifi-script-extensions PRIVATE ${PY_SOURCES})
+    target_link_libraries(minifi-script-extensions ${PYTHON_LIBRARIES})
+    target_link_libraries(minifi-script-extensions pybind11)
+
     target_include_directories(minifi-script-extensions PRIVATE python)
     target_include_directories(minifi-script-extensions SYSTEM PRIVATE ${PYTHON_INCLUDE_DIR})
     target_include_directories(minifi-script-extensions SYSTEM PRIVATE ../../thirdparty/pybind11/include)
@@ -65,13 +55,10 @@ if (ENABLE_LUA_SCRIPTING)
     add_definitions(-DLUA_SUPPORT)
 
     file(GLOB LUA_SOURCES  "lua/*.cpp")
-    add_library(minifi-lua-extensions STATIC ${LUA_SOURCES})
-
-    target_link_libraries(minifi-lua-extensions ${LIBMINIFI})
-    target_link_libraries(minifi-lua-extensions ${LUA_LIBRARIES} sol2)
-    target_link_libraries(minifi-script-extensions minifi-lua-extensions)
+    target_sources(minifi-script-extensions PRIVATE ${LUA_SOURCES})
 
-    target_compile_features(minifi-lua-extensions PUBLIC cxx_std_14)
+    target_link_libraries(minifi-script-extensions ${LUA_LIBRARIES} sol2)
+    target_compile_features(minifi-script-extensions PUBLIC cxx_std_14)
 endif()
 
 SET (SCRIPTING-EXTENSIONS minifi-script-extensions PARENT_SCOPE)
diff --git a/extensions/script/ExecuteScript.cpp b/extensions/script/ExecuteScript.cpp
index 381948a..4af4a1e 100644
--- a/extensions/script/ExecuteScript.cpp
+++ b/extensions/script/ExecuteScript.cpp
@@ -32,6 +32,7 @@
 #endif  // LUA_SUPPORT
 
 #include "ExecuteScript.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -155,6 +156,12 @@ void ExecuteScript::onTrigger(const std::shared_ptr<core::ProcessContext> &conte
   }
 }
 
+REGISTER_RESOURCE(ExecuteScript, "Executes a script given the flow file and a process session. The script is responsible for handling the incoming flow file (transfer to SUCCESS or remove, e.g.) "
+    "as well as any flow files created by the script. If the handling is incomplete or incorrect, the session will be rolled back.Scripts must define an onTrigger function which accepts NiFi Context"
+    " and Property objects. For efficiency, scripts are executed once when the processor is run, then the onTrigger method is called for each incoming flowfile. This enables scripts to keep state "
+    "if they wish, although there will be a script context per concurrent task of the processor. In order to, e.g., compute an arithmetic sum based on incoming flow file information, set the "
+    "concurrent tasks to 1."); // NOLINT
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/script/ExecuteScript.h b/extensions/script/ExecuteScript.h
index 9fab73f..09abf5f 100644
--- a/extensions/script/ExecuteScript.h
+++ b/extensions/script/ExecuteScript.h
@@ -24,7 +24,6 @@
 #include <memory>
 
 #include "concurrentqueue.h"
-#include "core/Resource.h"
 #include "core/Processor.h"
 
 #include "ScriptEngine.h"
@@ -90,12 +89,6 @@ class ExecuteScript : public core::Processor {
   }
 };
 
-REGISTER_RESOURCE(ExecuteScript, "Executes a script given the flow file and a process session. The script is responsible for handling the incoming flow file (transfer to SUCCESS or remove, e.g.) "
-    "as well as any flow files created by the script. If the handling is incomplete or incorrect, the session will be rolled back.Scripts must define an onTrigger function which accepts NiFi Context"
-    " and Property objects. For efficiency, scripts are executed once when the processor is run, then the onTrigger method is called for each incoming flowfile. This enables scripts to keep state "
-    "if they wish, although there will be a script context per concurrent task of the processor. In order to, e.g., compute an arithmetic sum based on incoming flow file information, set the "
-    "concurrent tasks to 1."); // NOLINT
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/script/python/ExecutePythonProcessor.cpp b/extensions/script/python/ExecutePythonProcessor.cpp
index a2eac7f..79a3667 100644
--- a/extensions/script/python/ExecutePythonProcessor.cpp
+++ b/extensions/script/python/ExecutePythonProcessor.cpp
@@ -26,6 +26,7 @@
 #include "ExecutePythonProcessor.h"
 
 #include "utils/StringUtils.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -181,6 +182,13 @@ void ExecutePythonProcessor::reloadScriptIfUsingScriptFileProperty() {
   }
 }
 
+REGISTER_RESOURCE(
+    ExecutePythonProcessor, "Executes a script given the flow file and a process session. The script is responsible for handling the incoming flow file (transfer to SUCCESS or remove, e.g.) "
+    "as well as any flow files created by the script. If the handling is incomplete or incorrect, the session will be rolled back.Scripts must define an onTrigger function which accepts NiFi Context"
+    " and Property objects. For efficiency, scripts are executed once when the processor is run, then the onTrigger method is called for each incoming flowfile. This enables scripts to keep state "
+    "if they wish, although there will be a script context per concurrent task of the processor. In order to, e.g., compute an arithmetic sum based on incoming flow file information, set the "
+    "concurrent tasks to 1.");  // NOLINT
+
 } /* namespace processors */
 } /* namespace python */
 } /* namespace minifi */
diff --git a/extensions/script/python/ExecutePythonProcessor.h b/extensions/script/python/ExecutePythonProcessor.h
index 3e50f8d..1ead86c 100644
--- a/extensions/script/python/ExecutePythonProcessor.h
+++ b/extensions/script/python/ExecutePythonProcessor.h
@@ -26,7 +26,6 @@
 #include <vector>
 
 #include "concurrentqueue.h"
-#include "core/Resource.h"
 #include "core/Processor.h"
 
 #include "../ScriptEngine.h"
@@ -52,12 +51,12 @@ class ExecutePythonProcessor : public core::Processor {
         script_engine_q_() {
   }
 
-  static core::Property ScriptFile;
-  static core::Property ScriptBody;
-  static core::Property ModuleDirectory;
+  EXTENSIONAPI static core::Property ScriptFile;
+  EXTENSIONAPI static core::Property ScriptBody;
+  EXTENSIONAPI static core::Property ModuleDirectory;
 
-  static core::Relationship Success;
-  static core::Relationship Failure;
+  EXTENSIONAPI static core::Relationship Success;
+  EXTENSIONAPI static core::Relationship Failure;
 
   void initialize() override;
   void onSchedule(const std::shared_ptr<core::ProcessContext> &context, const std::shared_ptr<core::ProcessSessionFactory> &sessionFactory) override;
@@ -127,13 +126,6 @@ class ExecutePythonProcessor : public core::Processor {
   }
 };
 
-REGISTER_RESOURCE(
-    ExecutePythonProcessor, "Executes a script given the flow file and a process session. The script is responsible for handling the incoming flow file (transfer to SUCCESS or remove, e.g.) "
-    "as well as any flow files created by the script. If the handling is incomplete or incorrect, the session will be rolled back.Scripts must define an onTrigger function which accepts NiFi Context"
-    " and Property objects. For efficiency, scripts are executed once when the processor is run, then the onTrigger method is called for each incoming flowfile. This enables scripts to keep state "
-    "if they wish, although there will be a script context per concurrent task of the processor. In order to, e.g., compute an arithmetic sum based on incoming flow file information, set the "
-    "concurrent tasks to 1.");  // NOLINT
-
 } /* namespace processors */
 } /* namespace python */
 } /* namespace minifi */
diff --git a/extensions/script/python/PyProcCreator.cpp b/extensions/script/python/PyProcCreator.cpp
deleted file mode 100644
index 0560209..0000000
--- a/extensions/script/python/PyProcCreator.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "PyProcCreator.h"
-
-PyProcCreator *PyProcCreator::getPythonCreator() {
-  static PyProcCreator python_the_creator;
-  return &python_the_creator;
-}
diff --git a/extensions/script/python/PythonCreator.cpp b/extensions/script/python/PythonCreator.cpp
deleted file mode 100644
index 81fa51d..0000000
--- a/extensions/script/python/PythonCreator.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "PythonCreator.h"
-
-#ifndef WIN32
-
-#include <sys/types.h>
-#include <dirent.h>
-#endif
-
-namespace org {
-namespace apache {
-namespace nifi {
-namespace minifi {
-namespace python {
-
-#ifndef S_ISDIR
-#define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
-#endif
-#ifndef R_OK
-#define R_OK    4       /* Test for read permission.  */
-#define W_OK    2       /* Test for write permission.  */
-#define F_OK    0       /* Test for existence.  */
-#endif
-PythonCreator::~PythonCreator() = default;
-
-} /* namespace python */
-} /* namespace minifi */
-} /* namespace nifi */
-} /* namespace apache */
-} /* namespace org */
diff --git a/extensions/script/python/PythonCreator.h b/extensions/script/python/PythonCreator.h
index 6d26e08..4977fab 100644
--- a/extensions/script/python/PythonCreator.h
+++ b/extensions/script/python/PythonCreator.h
@@ -25,8 +25,9 @@
 #include <memory>
 #include "core/Core.h"
 #include "core/logging/LoggerConfiguration.h"
+#include "core/Resource.h"
 #include "ExecutePythonProcessor.h"
-#include "PyProcCreator.h"
+#include "PythonObjectFactory.h"
 #include "agent/agent_version.h"
 #include "agent/build_description.h"
 #include "utils/file/FileUtils.h"
@@ -48,17 +49,9 @@ class PythonCreator : public minifi::core::CoreComponent {
         logger_(logging::LoggerFactory<PythonCreator>::getLogger()) {
   }
 
-  virtual ~PythonCreator();
-
-  void configure(const std::vector<std::string> &pythonFiles) {
-    std::vector<std::string> pathOrFiles;
-    for (const auto &path : pythonFiles) {
-      const auto vec = utils::StringUtils::split(path, ",");
-      pathOrFiles.insert(pathOrFiles.end(), vec.begin(), vec.end());
-    }
-
-    for (const auto &path : pathOrFiles) {
-      utils::file::FileUtils::addFilesMatchingExtension(logger_, path, ".py", classpaths_);
+  ~PythonCreator() override {
+    for (const auto& clazz : registered_classes_) {
+      core::getClassLoader().unregisterClass(clazz);
     }
   }
 
@@ -66,81 +59,73 @@ class PythonCreator : public minifi::core::CoreComponent {
     python::PythonScriptEngine::initialize();
 
     auto engine = std::make_shared<python::PythonScriptEngine>();
-    std::string pathListings;
-
-    // assuming we have the options set and can access the PythonCreator
-
-    if (configuration->get("nifi.python.processor.dir", pathListings)) {
-      std::vector<std::string> paths;
-      paths.emplace_back(pathListings);
-
-      configure(paths);
-
-      for (const auto &path : classpaths_) {
-        const auto &scriptname = getScriptName(path);
-        const auto &package = getPackage(pathListings, path);
-        if (!package.empty()) {
-          std::string script_with_package = "org.apache.nifi.minifi.processors." + package + "." + scriptname;
-          PyProcCreator::getPythonCreator()->addClassName(script_with_package, path);
-        } else {
-          // maintain backwards compatibility with the standard package.
-          PyProcCreator::getPythonCreator()->addClassName(scriptname, path);
-        }
+    std::optional<std::string> pathListings = configuration ? configuration->get("nifi.python.processor.dir") : std::nullopt;
+    if (!pathListings) {
+      return;
+    }
+    configure({pathListings.value()});
+
+    for (const auto &path : classpaths_) {
+      const auto scriptname = getScriptName(path);
+      const auto package = getPackage(pathListings.value(), path);
+      std::string classname = scriptname;
+      std::string fullname = "org.apache.nifi.minifi.processors." + scriptname;
+      if (!package.empty()) {
+        fullname = utils::StringUtils::join_pack("org.apache.nifi.minifi.processors.", package, ".", scriptname);
+        classname = fullname;
       }
-
-      core::ClassLoader::getDefaultClassLoader().registerResource("", "createPyProcFactory");
-
-      for (const auto &path : classpaths_) {
-        const auto &scriptName = getScriptName(path);
-
-        utils::Identifier uuid;
-
-        std::string loadName = scriptName;
-        const auto &package = getPackage(pathListings, path);
-
-        if (!package.empty())
-          loadName = "org.apache.nifi.minifi.processors." + package + "." + scriptName;
-
-        auto processor = std::dynamic_pointer_cast<core::Processor>(core::ClassLoader::getDefaultClassLoader().instantiate(loadName, uuid));
-        if (processor) {
-          try {
-            processor->initialize();
-            auto proc = std::dynamic_pointer_cast<python::processors::ExecutePythonProcessor>(processor);
-            minifi::BundleDetails details;
-            const auto &package = getPackage(pathListings, path);
-            std::string script_with_package = "org.apache.nifi.minifi.processors.";
-            if (!package.empty()) {
-              script_with_package += package + ".";
-            }
-            script_with_package += scriptName;
-            details.artifact = getFileName(path);
-            details.version = minifi::AgentBuild::VERSION;
-            details.group = "python";
-
-            minifi::ClassDescription description(script_with_package);
-            description.dynamic_properties_ = proc->getPythonSupportDynamicProperties();
-            description.inputRequirement_ = proc->getInputRequirementAsString();
-            auto properties = proc->getPythonProperties();
-
-            minifi::AgentDocs::putDescription(scriptName, proc->getDescription());
-            for (const auto &prop : properties) {
-              description.class_properties_.insert(std::make_pair(prop.getName(), prop));
-            }
-
-            for (const auto &rel : proc->getSupportedRelationships()) {
-              description.class_relationships_.push_back(rel);
-            }
-            minifi::ExternalBuildDescription::addExternalComponent(details, description);
-          } catch (const std::exception &e) {
-            logger_->log_warn("Cannot load %s because of %s", scriptName, e.what());
-          }
-        }
+      core::getClassLoader().registerClass(classname, std::make_unique<PythonObjectFactory>(path, classname));
+      registered_classes_.push_back(classname);
+      try {
+        registerScriptDescription(classname, fullname, path, scriptname);
+      } catch (const std::exception &err) {
+        logger_->log_error("Cannot load %s: %s", scriptname, err.what());
       }
     }
   }
 
  private:
-  std::string getPackage(const std::string &basePath, const std::string pythonscript) {
+  void registerScriptDescription(const std::string& classname, const std::string& fullname, const std::string& path, const std::string& scriptname) {
+    auto processor = core::ClassLoader::getDefaultClassLoader().instantiate<python::processors::ExecutePythonProcessor>(classname, utils::IdGenerator::getIdGenerator()->generate());
+    if (!processor) {
+      logger_->log_error("Couldn't instantiate '%s' python processor", classname);
+      return;
+    }
+    processor->initialize();
+    minifi::BundleDetails details;
+    details.artifact = getFileName(path);
+    details.version = minifi::AgentBuild::VERSION;
+    details.group = "python";
+
+    minifi::ClassDescription description(fullname);
+    description.dynamic_properties_ = processor->getPythonSupportDynamicProperties();
+    description.inputRequirement_ = processor->getInputRequirementAsString();
+    auto properties = processor->getPythonProperties();
+
+    minifi::AgentDocs::putDescription(scriptname, processor->getDescription());
+    for (const auto &prop : properties) {
+      description.class_properties_.insert(std::make_pair(prop.getName(), prop));
+    }
+
+    for (const auto &rel : processor->getSupportedRelationships()) {
+      description.class_relationships_.push_back(rel);
+    }
+    minifi::ExternalBuildDescription::addExternalComponent(details, description);
+  }
+
+  void configure(const std::vector<std::string> &pythonFiles) {
+    std::vector<std::string> pathOrFiles;
+    for (const auto &path : pythonFiles) {
+      const auto vec = utils::StringUtils::split(path, ",");
+      pathOrFiles.insert(pathOrFiles.end(), vec.begin(), vec.end());
+    }
+
+    for (const auto &path : pathOrFiles) {
+      utils::file::FileUtils::addFilesMatchingExtension(logger_, path, ".py", classpaths_);
+    }
+  }
+
+  std::string getPackage(const std::string& basePath, const std::string& pythonscript) {
     const auto script_directory = getPath(pythonscript);
     const auto loc = script_directory.find_first_of(basePath);
     if (loc != 0 || script_directory.size() <= basePath.size()) {
@@ -173,6 +158,7 @@ class PythonCreator : public minifi::core::CoreComponent {
     return path.substr(0, dot_i);
   }
 
+  std::vector<std::string> registered_classes_;
   std::vector<std::string> classpaths_;
 
   std::shared_ptr<logging::Logger> logger_;
diff --git a/extensions/script/python/PyProcCreator.h b/extensions/script/python/PythonObjectFactory.h
similarity index 79%
rename from extensions/script/python/PyProcCreator.h
rename to extensions/script/python/PythonObjectFactory.h
index bf2c00e..3a2ff26 100644
--- a/extensions/script/python/PyProcCreator.h
+++ b/extensions/script/python/PythonObjectFactory.h
@@ -68,31 +68,4 @@ class PythonObjectFactory : public core::DefautObjectFactory<minifi::python::pro
   std::string name_;
 };
 
-class PyProcCreator {
- public:
-  void addClassName(const std::string &name, std::string file) {
-    file_mapping_[name] = file;
-  }
-
-  static PyProcCreator *getPythonCreator();
-
-  std::vector<std::string> getClassNames() {
-    std::vector<std::string> class_names;
-    for (const auto &kv : file_mapping_) {
-      class_names.push_back(kv.first);
-    }
-    return class_names;
-  }
-
-  std::unique_ptr<core::ObjectFactory> assign(const std::string &class_name) {
-    auto mapping = file_mapping_.find(class_name);
-    if (mapping != file_mapping_.end()) {
-      return std::unique_ptr<core::ObjectFactory>(new PythonObjectFactory(mapping->second, mapping->first));
-    }
-    return nullptr;
-  }
-
-  std::map<std::string, std::string> file_mapping_;
-};
-
 #pragma GCC visibility pop
diff --git a/extensions/script/python/PythonScriptEngine.cpp b/extensions/script/python/PythonScriptEngine.cpp
index 2a857fc..0e2a380 100644
--- a/extensions/script/python/PythonScriptEngine.cpp
+++ b/extensions/script/python/PythonScriptEngine.cpp
@@ -18,7 +18,6 @@
 #include <memory>
 #include <string>
 
-#include "PythonBindings.h"
 #include "PythonScriptEngine.h"
 
 namespace org {
diff --git a/extensions/script/pythonloader/PyProcLoader.cpp b/extensions/script/pythonloader/PyProcLoader.cpp
index 0808a8d..b2c0802 100644
--- a/extensions/script/pythonloader/PyProcLoader.cpp
+++ b/extensions/script/pythonloader/PyProcLoader.cpp
@@ -15,15 +15,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include "core/FlowConfiguration.h"
-#include "PyProcLoader.h"
+#include "core/extension/Extension.h"
+#include "PythonCreator.h"
+#include "PythonBindings.h"
 
-bool PyProcFactory::added = core::FlowConfiguration::add_static_func("createPyProcFactory");
-
-extern "C" {
+static minifi::python::PythonCreator& getPythonCreator() {
+  static minifi::python::PythonCreator instance("PythonCreator");
+  return instance;
+}
 
-void *createPyProcFactory(void) {
-  return new PyProcFactory();
+static bool init(const std::shared_ptr<minifi::Configure>& config) {
+  getPythonCreator().configure(config);
+  return true;
 }
 
+static void deinit() {
+  // TODO(adebreceni): deinitialization is not implemented
 }
+
+REGISTER_EXTENSION("PythonExtension", init, deinit);
+
diff --git a/extensions/script/pythonloader/PyProcLoader.h b/extensions/script/pythonloader/PyProcLoader.h
deleted file mode 100644
index 57e6b7d..0000000
--- a/extensions/script/pythonloader/PyProcLoader.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <map>
-#include <string>
-#include <memory>
-#include <vector>
-#include "core/ClassLoader.h"
-#include "ExecutePythonProcessor.h"
-#include "utils/StringUtils.h"
-#include "PythonCreator.h"
-#include "PyProcCreator.h"
-
-class PyProcFactory : public core::ObjectFactory {
- public:
-  PyProcFactory() = default;
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  virtual std::string getName() {
-    return "PyProcFactory";
-  }
-
-  virtual std::string getClassName() {
-    return "PyProcFactory";
-  }
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  virtual std::vector<std::string> getClassNames() {
-    std::vector<std::string> class_names = PyProcCreator::getPythonCreator()->getClassNames();
-    class_names.push_back("PythonCreator");
-    return class_names;
-  }
-
-  virtual std::unique_ptr<ObjectFactory> assign(const std::string &class_name) {
-    if (utils::StringUtils::equalsIgnoreCase(class_name, "PythonCreator")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::python::PythonCreator>());
-    } else {
-      return PyProcCreator::getPythonCreator()->assign(class_name);
-    }
-  }
-
-  static bool added;
-};
-
-extern "C" {
-DLL_EXPORT void *createPyProcFactory(void);
-}
diff --git a/extensions/sensors/CMakeLists.txt b/extensions/sensors/CMakeLists.txt
index e330472..8f5b731 100644
--- a/extensions/sensors/CMakeLists.txt
+++ b/extensions/sensors/CMakeLists.txt
@@ -21,8 +21,7 @@ include(${CMAKE_SOURCE_DIR}/extensions/ExtensionHeader.txt)
 
 file(GLOB SOURCES  "*.cpp")
 
-add_library(minifi-sensors STATIC ${SOURCES})
-set_property(TARGET minifi-sensors PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-sensors SHARED ${SOURCES})
 
 target_link_libraries(minifi-sensors ${LIBMINIFI} Threads::Threads)
 
diff --git a/extensions/sensors/GetEnvironmentalSensors.cpp b/extensions/sensors/GetEnvironmentalSensors.cpp
index 351a4f3..194596c 100644
--- a/extensions/sensors/GetEnvironmentalSensors.cpp
+++ b/extensions/sensors/GetEnvironmentalSensors.cpp
@@ -34,6 +34,7 @@
 #include "core/logging/Logger.h"
 #include "core/ProcessContext.h"
 #include "core/Relationship.h"
+#include "core/Resource.h"
 #include "GetEnvironmentalSensors.h"
 #include "io/BufferStream.h"
 #include "io/StreamFactory.h"
@@ -142,6 +143,8 @@ void GetEnvironmentalSensors::onTrigger(const std::shared_ptr<core::ProcessConte
   }
 }
 
+REGISTER_RESOURCE(GetEnvironmentalSensors, "Provides sensor information from known sensors to include humidity and pressure data");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/sensors/GetEnvironmentalSensors.h b/extensions/sensors/GetEnvironmentalSensors.h
index d3557aa..437e41c 100644
--- a/extensions/sensors/GetEnvironmentalSensors.h
+++ b/extensions/sensors/GetEnvironmentalSensors.h
@@ -27,7 +27,6 @@
 #include "core/ProcessSession.h"
 #include "core/Core.h"
 #include "core/Property.h"
-#include "core/Resource.h"
 #include "utils/Id.h"
 #include "RTIMULib.h"
 #include "SensorBase.h"
@@ -73,8 +72,6 @@ class GetEnvironmentalSensors : public SensorBase {
   static std::shared_ptr<utils::IdGenerator> id_generator_;
 };
 
-REGISTER_RESOURCE(GetEnvironmentalSensors, "Provides sensor information from known sensors to include humidity and pressure data");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/sensors/GetMovementSensors.cpp b/extensions/sensors/GetMovementSensors.cpp
index 6823d40..5a971c8 100644
--- a/extensions/sensors/GetMovementSensors.cpp
+++ b/extensions/sensors/GetMovementSensors.cpp
@@ -33,6 +33,7 @@
 #include "core/logging/Logger.h"
 #include "core/ProcessContext.h"
 #include "core/Relationship.h"
+#include "core/Resource.h"
 #include "GetMovementSensors.h"
 #include "io/BufferStream.h"
 #include "io/StreamFactory.h"
@@ -89,6 +90,9 @@ void GetMovementSensors::onTrigger(const std::shared_ptr<core::ProcessContext>&
     session->transfer(flow_file_, Success);
   }
 }
+
+REGISTER_RESOURCE(GetMovementSensors, "Defines a processor that is able to retrieve sensor information from a class of known servo sensors");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/sensors/GetMovementSensors.h b/extensions/sensors/GetMovementSensors.h
index 0ea1374..80f92c1 100644
--- a/extensions/sensors/GetMovementSensors.h
+++ b/extensions/sensors/GetMovementSensors.h
@@ -27,7 +27,6 @@
 #include "core/ProcessSession.h"
 #include "core/Core.h"
 #include "core/Property.h"
-#include "core/Resource.h"
 #include "utils/Id.h"
 #include "SensorBase.h"
 #include "RTIMULib.h"
@@ -64,8 +63,6 @@ class GetMovementSensors : public SensorBase {
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(GetMovementSensors, "Defines a processor that is able to retrieve sensor information from a class of known servo sensors");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/sensors/SensorBase.h b/extensions/sensors/SensorBase.h
index 3d11a7c..84bfb58 100644
--- a/extensions/sensors/SensorBase.h
+++ b/extensions/sensors/SensorBase.h
@@ -28,7 +28,6 @@
 #include "core/ProcessSession.h"
 #include "core/Core.h"
 #include "core/Property.h"
-#include "core/Resource.h"
 #include "utils/Id.h"
 #include "RTIMULib.h"
 #include "RTMath.h"
diff --git a/extensions/sensors/SensorLoader.h b/extensions/sensors/SensorLoader.h
deleted file mode 100644
index 0da22fb..0000000
--- a/extensions/sensors/SensorLoader.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <vector>
-#include <string>
-#include <memory>
-
-#include "core/ClassLoader.h"
-#include "GetEnvironmentalSensors.h"
-#include "GetMovementSensors.h"
-#include "utils/StringUtils.h"
-
-class SensorFactory : public core::ObjectFactory {
- public:
-  SensorFactory() = default;
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  virtual std::string getName() {
-    return "SensorFactory";
-  }
-
-  virtual std::string getClassName() {
-    return "SensorFactory";
-  }
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  virtual std::vector<std::string> getClassNames() {
-    std::vector<std::string> class_names;
-    class_names.push_back("EnvironmentalSensors");
-    return class_names;
-  }
-
-  virtual std::unique_ptr<ObjectFactory> assign(const std::string &class_name) {
-    if (minifi::utils::StringUtils::equalsIgnoreCase(class_name, "GetEnvironmentalSensors")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::processors::GetEnvironmentalSensors>());
-    } else if (minifi::utils::StringUtils::equalsIgnoreCase(class_name, "GetMovementSensors")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::processors::GetMovementSensors>());
-    } else {
-      return nullptr;
-    }
-  }
-
-  static bool added;
-};
-
-extern "C" {
-DLL_EXPORT void *createSensorFactory(void);
-}
diff --git a/extensions/sftp/CMakeLists.txt b/extensions/sftp/CMakeLists.txt
index 7032fb2..6b092b2 100644
--- a/extensions/sftp/CMakeLists.txt
+++ b/extensions/sftp/CMakeLists.txt
@@ -22,8 +22,7 @@ include_directories(client processors)
 
 file(GLOB SOURCES  "*.cpp" "client/*.cpp" "processors/*.cpp")
 
-add_library(minifi-sftp STATIC ${SOURCES})
-set_property(TARGET minifi-sftp PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-sftp SHARED ${SOURCES})
 
 target_link_libraries(minifi-sftp ${LIBMINIFI} Threads::Threads)
 target_link_libraries(minifi-sftp CURL::libcurl libssh2 RapidJSON)
diff --git a/extensions/sftp/SFTPLoader.cpp b/extensions/sftp/SFTPLoader.cpp
index 272da99..2e6a8d2 100644
--- a/extensions/sftp/SFTPLoader.cpp
+++ b/extensions/sftp/SFTPLoader.cpp
@@ -15,11 +15,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include "SFTPLoader.h"
-#include "core/FlowConfiguration.h"
+
+#include "core/extension/Extension.h"
 #include "client/SFTPClient.h"
 
-bool SFTPFactoryInitializer::initialize() {
+static bool init(const std::shared_ptr<org::apache::nifi::minifi::Configure>& /*config*/) {
   if (libssh2_init(0) != 0) {
     return false;
   }
@@ -30,18 +30,9 @@ bool SFTPFactoryInitializer::initialize() {
   return true;
 }
 
-void SFTPFactoryInitializer::deinitialize() {
+static void deinit() {
   curl_global_cleanup();
   libssh2_exit();
 }
 
-
-bool SFTPFactory::added = core::FlowConfiguration::add_static_func("createSFTPFactory");
-
-extern "C" {
-
-void *createSFTPFactory(void) {
-  return new SFTPFactory();
-}
-
-}
+REGISTER_EXTENSION("SFTPExtension", init, deinit);
diff --git a/extensions/sftp/SFTPLoader.h b/extensions/sftp/SFTPLoader.h
deleted file mode 100644
index 4e29468..0000000
--- a/extensions/sftp/SFTPLoader.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <vector>
-#include <string>
-#include <memory>
-
-#include "core/ClassLoader.h"
-#include "processors/PutSFTP.h"
-#include "processors/FetchSFTP.h"
-#include "processors/ListSFTP.h"
-
-class SFTPFactoryInitializer : public core::ObjectFactoryInitializer {
- public:
-  virtual bool initialize();
-  virtual void deinitialize();
-};
-
-class SFTPFactory : public core::ObjectFactory {
- public:
-  SFTPFactory() = default;
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  virtual std::string getName() {
-    return "SFTPFactory";
-  }
-
-  virtual std::string getClassName() {
-    return "SFTPFactory";
-  }
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  virtual std::vector<std::string> getClassNames() {
-    std::vector<std::string> class_names;
-    class_names.push_back("PutSFTP");
-    return class_names;
-  }
-
-  virtual std::unique_ptr<ObjectFactory> assign(const std::string &class_name) {
-    if (utils::StringUtils::equalsIgnoreCase(class_name, "PutSFTP")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::processors::PutSFTP>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "FetchSFTP")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::processors::FetchSFTP>());
-    } else if (utils::StringUtils::equalsIgnoreCase(class_name, "ListSFTP")) {
-      return std::unique_ptr<ObjectFactory>(new core::DefautObjectFactory<minifi::processors::ListSFTP>());
-    } else {
-      return nullptr;
-    }
-  }
-
-  virtual std::unique_ptr<core::ObjectFactoryInitializer> getInitializer() {
-    return std::unique_ptr<core::ObjectFactoryInitializer>(new SFTPFactoryInitializer());
-  }
-
-  static bool added;
-};
-
-extern "C" {
-DLL_EXPORT void *createSFTPFactory(void);
-}
diff --git a/extensions/sftp/processors/FetchSFTP.cpp b/extensions/sftp/processors/FetchSFTP.cpp
index d7fcf9b..5326b9d 100644
--- a/extensions/sftp/processors/FetchSFTP.cpp
+++ b/extensions/sftp/processors/FetchSFTP.cpp
@@ -34,6 +34,7 @@
 #include "core/logging/Logger.h"
 #include "core/ProcessContext.h"
 #include "core/Relationship.h"
+#include "core/Resource.h"
 #include "io/BufferStream.h"
 #include "io/StreamFactory.h"
 #include "ResourceClaim.h"
@@ -284,6 +285,8 @@ void FetchSFTP::onTrigger(const std::shared_ptr<core::ProcessContext> &context,
   put_connection_back_to_cache();
 }
 
+REGISTER_RESOURCE(FetchSFTP, "Fetches the content of a file from a remote SFTP server and overwrites the contents of an incoming FlowFile with the content of the remote file.");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/sftp/processors/FetchSFTP.h b/extensions/sftp/processors/FetchSFTP.h
index 2da6fb0..d8dce60 100644
--- a/extensions/sftp/processors/FetchSFTP.h
+++ b/extensions/sftp/processors/FetchSFTP.h
@@ -26,7 +26,6 @@
 #include "core/ProcessSession.h"
 #include "core/Core.h"
 #include "core/Property.h"
-#include "core/Resource.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "utils/Id.h"
 #include "../client/SFTPClient.h"
@@ -98,8 +97,6 @@ class FetchSFTP : public SFTPProcessorBase {
   bool disable_directory_listing_;
 };
 
-REGISTER_RESOURCE(FetchSFTP, "Fetches the content of a file from a remote SFTP server and overwrites the contents of an incoming FlowFile with the content of the remote file.");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/sftp/processors/ListSFTP.cpp b/extensions/sftp/processors/ListSFTP.cpp
index dc17837..9c4f91a 100644
--- a/extensions/sftp/processors/ListSFTP.cpp
+++ b/extensions/sftp/processors/ListSFTP.cpp
@@ -44,6 +44,7 @@
 #include "core/logging/Logger.h"
 #include "core/ProcessContext.h"
 #include "core/Relationship.h"
+#include "core/Resource.h"
 #include "io/BufferStream.h"
 #include "io/StreamFactory.h"
 #include "ResourceClaim.h"
@@ -1071,6 +1072,11 @@ void ListSFTP::onTrigger(const std::shared_ptr<core::ProcessContext> &context, c
   put_connection_back_to_cache();
 }
 
+REGISTER_RESOURCE(ListSFTP, "Performs a listing of the files residing on an SFTP server. "
+                            "For each file that is found on the remote server, a new FlowFile will be created with "
+                            "the filename attribute set to the name of the file on the remote server. "
+                            "This can then be used in conjunction with FetchSFTP in order to fetch those files.");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/sftp/processors/ListSFTP.h b/extensions/sftp/processors/ListSFTP.h
index 74b9d27..d981d34 100644
--- a/extensions/sftp/processors/ListSFTP.h
+++ b/extensions/sftp/processors/ListSFTP.h
@@ -31,7 +31,6 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Property.h"
-#include "core/Resource.h"
 #include "utils/Id.h"
 #include "controllers/keyvalue/PersistableKeyValueStoreService.h"
 
@@ -194,11 +193,6 @@ class ListSFTP : public SFTPProcessorBase {
       std::vector<Child>&& files);
 };
 
-REGISTER_RESOURCE(ListSFTP, "Performs a listing of the files residing on an SFTP server. "
-                            "For each file that is found on the remote server, a new FlowFile will be created with "
-                            "the filename attribute set to the name of the file on the remote server. "
-                            "This can then be used in conjunction with FetchSFTP in order to fetch those files.");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/sftp/processors/PutSFTP.cpp b/extensions/sftp/processors/PutSFTP.cpp
index 16d0b84..a794dbe 100644
--- a/extensions/sftp/processors/PutSFTP.cpp
+++ b/extensions/sftp/processors/PutSFTP.cpp
@@ -37,6 +37,7 @@
 #include "core/logging/Logger.h"
 #include "core/ProcessContext.h"
 #include "core/Relationship.h"
+#include "core/Resource.h"
 #include "io/BufferStream.h"
 #include "io/StreamFactory.h"
 #include "ResourceClaim.h"
@@ -506,6 +507,8 @@ void PutSFTP::onTrigger(const std::shared_ptr<core::ProcessContext> &context, co
   }
 }
 
+REGISTER_RESOURCE(PutSFTP, "Sends FlowFiles to an SFTP Server");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/sftp/processors/PutSFTP.h b/extensions/sftp/processors/PutSFTP.h
index 76c13ee..4aceeca 100644
--- a/extensions/sftp/processors/PutSFTP.h
+++ b/extensions/sftp/processors/PutSFTP.h
@@ -32,7 +32,6 @@
 #include "core/ProcessSession.h"
 #include "core/Core.h"
 #include "core/Property.h"
-#include "core/Resource.h"
 #include "controllers/SSLContextService.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "utils/Id.h"
@@ -119,8 +118,6 @@ class PutSFTP : public SFTPProcessorBase {
   bool processOne(const std::shared_ptr<core::ProcessContext> &context, const std::shared_ptr<core::ProcessSession> &session);
 };
 
-REGISTER_RESOURCE(PutSFTP, "Sends FlowFiles to an SFTP Server");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/sftp/tests/CMakeLists.txt b/extensions/sftp/tests/CMakeLists.txt
index e9936d3..89394cc 100644
--- a/extensions/sftp/tests/CMakeLists.txt
+++ b/extensions/sftp/tests/CMakeLists.txt
@@ -42,12 +42,12 @@ if (NOT SKIP_TESTS AND Java_FOUND AND Maven_FOUND AND NOT DISABLE_EXPRESSION_LAN
 		target_include_directories(${testfilename} BEFORE PRIVATE ./tools)
 
 		createTests("${testfilename}")
-		target_link_libraries(${testfilename} ${CATCH_MAIN_LIB} minifi sftp-test-tools)
-		target_wholearchive_library(${testfilename} minifi-sftp)
-		target_wholearchive_library(${testfilename} minifi-expression-language-extensions)
-		target_wholearchive_library(${testfilename} minifi-standard-processors)
+		target_link_libraries(${testfilename} ${CATCH_MAIN_LIB} core-minifi sftp-test-tools)
+		target_link_libraries(${testfilename} minifi-sftp)
+		target_link_libraries(${testfilename} minifi-expression-language-extensions)
+		target_link_libraries(${testfilename} minifi-standard-processors)
 		if (NOT DISABLE_ROCKSDB)
-			target_wholearchive_library(${testfilename} minifi-rocksdb-repos)
+			target_link_libraries(${testfilename} minifi-rocksdb-repos)
 		endif()
 
 		MATH(EXPR SFTP-EXTENSIONS_TEST_COUNT "${SFTP-EXTENSIONS_TEST_COUNT}+1")
@@ -56,7 +56,7 @@ if (NOT SKIP_TESTS AND Java_FOUND AND Maven_FOUND AND NOT DISABLE_EXPRESSION_LAN
 	message("-- Finished building ${SFTP-EXTENSIONS_TEST_COUNT} SFTP related test file(s)...")
 
 	# Copy test resources
-	file(COPY "${CMAKE_SOURCE_DIR}/extensions/sftp/tests/resources" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/")
+	file(COPY "${CMAKE_SOURCE_DIR}/extensions/sftp/tests/resources" DESTINATION "${CMAKE_BINARY_DIR}/bin/sftp-test/")
 
 	add_subdirectory(tools)
 else()
diff --git a/extensions/sftp/tests/FetchSFTPTests.cpp b/extensions/sftp/tests/FetchSFTPTests.cpp
index 84b6f05..460fb7b 100644
--- a/extensions/sftp/tests/FetchSFTPTests.cpp
+++ b/extensions/sftp/tests/FetchSFTPTests.cpp
@@ -216,7 +216,7 @@ TEST_CASE_METHOD(FetchSFTPTestsFixture, "FetchSFTP fetch one file", "[FetchSFTP]
 
 TEST_CASE_METHOD(FetchSFTPTestsFixture, "FetchSFTP public key authentication", "[FetchSFTP][basic]") {
   plan->setProperty(fetch_sftp, "Remote File", "nifi_test/tstFile.ext");
-  plan->setProperty(fetch_sftp, "Private Key Path", utils::file::FileUtils::concat_path(utils::file::FileUtils::get_executable_dir(), "resources/id_rsa"));
+  plan->setProperty(fetch_sftp, "Private Key Path", utils::file::FileUtils::concat_path(get_sftp_test_dir(), "resources/id_rsa"));
   plan->setProperty(fetch_sftp, "Private Key Passphrase", "privatekeypassword");
 
   createFile("nifi_test/tstFile.ext", "Test content 1");
@@ -383,7 +383,7 @@ TEST_CASE_METHOD(FetchSFTPTestsFixture, "FetchSFTP expression language test", "[
   plan->setProperty(update_attribute, "attr_Username", "nifiuser", true /*dynamic*/);
   plan->setProperty(update_attribute, "attr_Password", "nifipassword", true /*dynamic*/);
   plan->setProperty(update_attribute, "attr_Private Key Path",
-  utils::file::FileUtils::concat_path(utils::file::FileUtils::get_executable_dir(), "resources/id_rsa"), true /*dynamic*/);
+    utils::file::FileUtils::concat_path(get_sftp_test_dir(), "resources/id_rsa"), true /*dynamic*/);
   plan->setProperty(update_attribute, "attr_Private Key Passphrase", "privatekeypassword", true /*dynamic*/);
   plan->setProperty(update_attribute, "attr_Remote File", "nifi_test/tstFile.ext", true /*dynamic*/);
   plan->setProperty(update_attribute, "attr_Move Destination Directory", "nifi_done/", true /*dynamic*/);
diff --git a/extensions/sftp/tests/ListSFTPTests.cpp b/extensions/sftp/tests/ListSFTPTests.cpp
index 25f9f45..cc88eac 100644
--- a/extensions/sftp/tests/ListSFTPTests.cpp
+++ b/extensions/sftp/tests/ListSFTPTests.cpp
@@ -186,7 +186,7 @@ TEST_CASE_METHOD(ListSFTPTestsFixture, "ListSFTP list one file", "[ListSFTP][bas
 
 TEST_CASE_METHOD(ListSFTPTestsFixture, "ListSFTP public key authentication", "[ListSFTP][basic]") {
   plan->setProperty(list_sftp, "Remote File", "nifi_test/tstFile.ext");
-  plan->setProperty(list_sftp, "Private Key Path", utils::file::FileUtils::concat_path(utils::file::FileUtils::get_executable_dir(), "resources/id_rsa"));
+  plan->setProperty(list_sftp, "Private Key Path", utils::file::FileUtils::concat_path(get_sftp_test_dir(), "resources/id_rsa"));
   plan->setProperty(list_sftp, "Private Key Passphrase", "privatekeypassword");
 
   createFileWithModificationTimeDiff("nifi_test/tstFile.ext", "Test content 1");
diff --git a/extensions/sftp/tests/PutSFTPTests.cpp b/extensions/sftp/tests/PutSFTPTests.cpp
index 2449eb2..8309d98 100644
--- a/extensions/sftp/tests/PutSFTPTests.cpp
+++ b/extensions/sftp/tests/PutSFTPTests.cpp
@@ -242,7 +242,7 @@ TEST_CASE_METHOD(PutSFTPTestsFixture, "PutSFTP bad password", "[PutSFTP][authent
 }
 
 TEST_CASE_METHOD(PutSFTPTestsFixture, "PutSFTP public key authentication success", "[PutSFTP][authentication]") {
-  plan->setProperty(put, "Private Key Path", utils::file::FileUtils::concat_path(utils::file::FileUtils::get_executable_dir(), "resources/id_rsa"));
+  plan->setProperty(put, "Private Key Path", utils::file::FileUtils::concat_path(get_sftp_test_dir(), "resources/id_rsa"));
   plan->setProperty(put, "Private Key Passphrase", "privatekeypassword");
 
   createFile(src_dir, "tstFile.ext", "tempFile");
@@ -255,7 +255,7 @@ TEST_CASE_METHOD(PutSFTPTestsFixture, "PutSFTP public key authentication success
 
 TEST_CASE_METHOD(PutSFTPTestsFixture, "PutSFTP public key authentication bad passphrase", "[PutSFTP][authentication]") {
   plan->setProperty(put, "Password", "");
-  plan->setProperty(put, "Private Key Path", utils::file::FileUtils::concat_path(utils::file::FileUtils::get_executable_dir(), "resources/id_rsa"));
+  plan->setProperty(put, "Private Key Path", utils::file::FileUtils::concat_path(get_sftp_test_dir(), "resources/id_rsa"));
   plan->setProperty(put, "Private Key Passphrase", "badpassword");
 
   createFile(src_dir, "tstFile.ext", "tempFile");
@@ -271,7 +271,7 @@ TEST_CASE_METHOD(PutSFTPTestsFixture, "PutSFTP public key authentication bad pas
 }
 
 TEST_CASE_METHOD(PutSFTPTestsFixture, "PutSFTP public key authentication bad passphrase fallback to password", "[PutSFTP][authentication]") {
-  plan->setProperty(put, "Private Key Path", utils::file::FileUtils::concat_path(utils::file::FileUtils::get_executable_dir(), "resources/id_rsa"));
+  plan->setProperty(put, "Private Key Path", utils::file::FileUtils::concat_path(get_sftp_test_dir(), "resources/id_rsa"));
   plan->setProperty(put, "Private Key Passphrase", "badpassword");
 
   createFile(src_dir, "tstFile.ext", "tempFile");
@@ -284,7 +284,7 @@ TEST_CASE_METHOD(PutSFTPTestsFixture, "PutSFTP public key authentication bad pas
 }
 
 TEST_CASE_METHOD(PutSFTPTestsFixture, "PutSFTP host key checking success", "[PutSFTP][hostkey]") {
-  plan->setProperty(put, "Host Key File", utils::file::FileUtils::concat_path(utils::file::FileUtils::get_executable_dir(), "resources/known_hosts"));
+  plan->setProperty(put, "Host Key File", utils::file::FileUtils::concat_path(get_sftp_test_dir(), "resources/known_hosts"));
   plan->setProperty(put, "Strict Host Key Checking", "true");
 
   createFile(src_dir, "tstFile.ext", "tempFile");
@@ -298,7 +298,7 @@ TEST_CASE_METHOD(PutSFTPTestsFixture, "PutSFTP host key checking success", "[Put
 TEST_CASE_METHOD(PutSFTPTestsFixture, "PutSFTP host key checking missing strict", "[PutSFTP][hostkey]") {
   plan->setProperty(put, "Hostname", "127.0.0.1");
 
-  plan->setProperty(put, "Host Key File", utils::file::FileUtils::concat_path(utils::file::FileUtils::get_executable_dir(), "resources/known_hosts"));
+  plan->setProperty(put, "Host Key File", utils::file::FileUtils::concat_path(get_sftp_test_dir(), "resources/known_hosts"));
   plan->setProperty(put, "Strict Host Key Checking", "true");
 
   createFile(src_dir, "tstFile.ext", "tempFile");
@@ -316,7 +316,7 @@ TEST_CASE_METHOD(PutSFTPTestsFixture, "PutSFTP host key checking missing strict"
 TEST_CASE_METHOD(PutSFTPTestsFixture, "PutSFTP host key checking missing non-strict", "[PutSFTP][hostkey]") {
   plan->setProperty(put, "Hostname", "127.0.0.1");
 
-  plan->setProperty(put, "Host Key File", utils::file::FileUtils::concat_path(utils::file::FileUtils::get_executable_dir(), "resources/known_hosts"));
+  plan->setProperty(put, "Host Key File", utils::file::FileUtils::concat_path(get_sftp_test_dir(), "resources/known_hosts"));
   plan->setProperty(put, "Strict Host Key Checking", "false");
 
   createFile(src_dir, "tstFile.ext", "tempFile");
@@ -328,7 +328,7 @@ TEST_CASE_METHOD(PutSFTPTestsFixture, "PutSFTP host key checking missing non-str
 }
 
 TEST_CASE_METHOD(PutSFTPTestsFixture, "PutSFTP host key checking mismatch strict", "[PutSFTP][hostkey]") {
-  plan->setProperty(put, "Host Key File", utils::file::FileUtils::concat_path(utils::file::FileUtils::get_executable_dir(), "resources/known_hosts_mismatch"));
+  plan->setProperty(put, "Host Key File", utils::file::FileUtils::concat_path(get_sftp_test_dir(), "resources/known_hosts_mismatch"));
   plan->setProperty(put, "Strict Host Key Checking", "true");
 
   createFile(src_dir, "tstFile.ext", "tempFile");
@@ -843,7 +843,7 @@ TEST_CASE_METHOD(PutSFTPTestsFixture, "PutSFTP expression language test", "[PutS
   plan->setProperty(update_attribute, "attr_Username", "nifiuser", true /*dynamic*/);
   plan->setProperty(update_attribute, "attr_Password", "nifipassword", true /*dynamic*/);
   plan->setProperty(update_attribute, "attr_Private Key Path",
-      utils::file::FileUtils::concat_path(utils::file::FileUtils::get_executable_dir(), "resources/id_rsa"), true /*dynamic*/);
+      utils::file::FileUtils::concat_path(get_sftp_test_dir(), "resources/id_rsa"), true /*dynamic*/);
   plan->setProperty(update_attribute, "attr_Private Key Passphrase", "privatekeypassword", true /*dynamic*/);
   plan->setProperty(update_attribute, "attr_Remote Path", "nifi_test/", true /*dynamic*/);
   plan->setProperty(update_attribute, "attr_Temporary Filename", "tempfile", true /*dynamic*/);
diff --git a/extensions/sftp/tests/tools/CMakeLists.txt b/extensions/sftp/tests/tools/CMakeLists.txt
index c42fe0d..d1f9701 100644
--- a/extensions/sftp/tests/tools/CMakeLists.txt
+++ b/extensions/sftp/tests/tools/CMakeLists.txt
@@ -27,10 +27,10 @@ target_include_directories(sftp-test-tools BEFORE PRIVATE "${CMAKE_SOURCE_DIR}/l
 target_include_directories(sftp-test-tools BEFORE PRIVATE "${CMAKE_SOURCE_DIR}/libminifi/include/core")
 target_include_directories(sftp-test-tools BEFORE PRIVATE "${CMAKE_SOURCE_DIR}/libminifi/include/io")
 
-target_link_libraries(sftp-test-tools minifi)
+target_link_libraries(sftp-test-tools core-minifi)
 
 set(SFTP_TEST_SERVER_JAR_SOURCE "${CMAKE_SOURCE_DIR}/extensions/sftp/tests/tools/sftp-test-server")
-set(SFTP_TEST_SERVER_JAR_BIN "${CMAKE_CURRENT_BINARY_DIR}/" )
+set(SFTP_TEST_SERVER_JAR_BIN "${CMAKE_BINARY_DIR}/bin/sftp-test/tools" )
 
 file(COPY ${SFTP_TEST_SERVER_JAR_SOURCE} DESTINATION ${SFTP_TEST_SERVER_JAR_BIN})
 
diff --git a/extensions/sftp/tests/tools/SFTPTestServer.cpp b/extensions/sftp/tests/tools/SFTPTestServer.cpp
index 6ab788a..fd086d5 100644
--- a/extensions/sftp/tests/tools/SFTPTestServer.cpp
+++ b/extensions/sftp/tests/tools/SFTPTestServer.cpp
@@ -44,9 +44,8 @@ SFTPTestServer::SFTPTestServer(const std::string& working_directory,
       , server_pid_(-1)
 #endif
 {
-  auto executable_dir = utils::file::FileUtils::get_executable_dir();
-  host_key_file_ = utils::file::FileUtils::concat_path(executable_dir, host_key_file);
-  jar_path_ = utils::file::FileUtils::concat_path(executable_dir, jar_path);
+  host_key_file_ = utils::file::FileUtils::concat_path(get_sftp_test_dir(), host_key_file);
+  jar_path_ = utils::file::FileUtils::concat_path(get_sftp_test_dir(), jar_path);
 }
 
 SFTPTestServer::~SFTPTestServer() {
@@ -143,3 +142,7 @@ bool SFTPTestServer::stop() {
 uint16_t SFTPTestServer::getPort() {
   return port_;
 }
+
+std::string get_sftp_test_dir() {
+  return utils::file::FileUtils::concat_path(utils::file::FileUtils::get_executable_dir(), "sftp-test");
+}
diff --git a/extensions/sftp/tests/tools/SFTPTestServer.h b/extensions/sftp/tests/tools/SFTPTestServer.h
index 9acf377..2484f98 100644
--- a/extensions/sftp/tests/tools/SFTPTestServer.h
+++ b/extensions/sftp/tests/tools/SFTPTestServer.h
@@ -29,6 +29,8 @@
 #include "core/logging/Logger.h"
 #include "core/logging/LoggerConfiguration.h"
 
+std::string get_sftp_test_dir();
+
 class SFTPTestServer {
  public:
   SFTPTestServer(const std::string& working_directory,
diff --git a/extensions/sql/CMakeLists.txt b/extensions/sql/CMakeLists.txt
index 3381e05..c6f67e5 100644
--- a/extensions/sql/CMakeLists.txt
+++ b/extensions/sql/CMakeLists.txt
@@ -24,8 +24,7 @@ include_directories(".")
 
 file(GLOB SOURCES  "*.cpp" "services/*.cpp" "processors/*.cpp"  "data/*.cpp")
 
-add_library(minifi-sql STATIC ${SOURCES})
-set_property(TARGET minifi-sql PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-sql SHARED ${SOURCES})
 
 if(WIN32)
 	find_package(ODBC REQUIRED)
@@ -48,7 +47,7 @@ else()
 			CMAKE_COMMAND ""
 			UPDATE_COMMAND ""
 			INSTALL_COMMAND make install
-			CONFIGURE_COMMAND ./autogen.sh && ./configure --prefix=${IODBC_BYPRODUCT_DIR}
+			CONFIGURE_COMMAND ./autogen.sh && ./configure --prefix=${IODBC_BYPRODUCT_DIR} --with-pic
 			STEP_TARGETS build
 			BUILD_BYPRODUCTS "${IODBC_BYPRODUCT_DIR}/${IODBC_BYPRODUCT}"
 			EXCLUDE_FROM_ALL TRUE
diff --git a/extensions/sql/SQLLoader.cpp b/extensions/sql/SQLLoader.cpp
deleted file mode 100644
index 2a787c2..0000000
--- a/extensions/sql/SQLLoader.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "core/FlowConfiguration.h"
-#include "SQLLoader.h"
-
-static auto added = core::FlowConfiguration::add_static_func("createSQLFactory");
-
-extern "C" {
-
-void *createSQLFactory(void) {
-  return new SQLFactory();
-}
-
-}
diff --git a/extensions/sql/SQLLoader.h b/extensions/sql/SQLLoader.h
deleted file mode 100644
index d3d050b..0000000
--- a/extensions/sql/SQLLoader.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <memory>
-
-#include "core/ClassLoader.h"
-#include "processors/ExecuteSQL.h"
-#include "processors/PutSQL.h"
-#include "processors/QueryDatabaseTable.h"
-#include "services/ODBCConnector.h"
-
-class SQLFactory : public core::ObjectFactory {
- public:
-  SQLFactory() = default;
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  std::string getName() override {
-    return "SQLFactory";
-  }
-
-  std::string getClassName() override {
-    return "SQLFactory";
-  }
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  std::vector<std::string> getClassNames() override {
-    return {"ExecuteSQL", "PutSQL", "QueryDatabaseTable", "ODBCService"};
-  }
-
-  template <typename T>
-  static std::unique_ptr<ObjectFactory> getObjectFactory() {
-    return std::make_unique<core::DefautObjectFactory<T>>();
-  }
-
-  std::unique_ptr<ObjectFactory> assign(const std::string &class_name) override {
-    if (utils::StringUtils::equalsIgnoreCase(class_name, "ExecuteSQL")) {
-      return getObjectFactory<minifi::processors::ExecuteSQL>();
-    }
-    if (utils::StringUtils::equalsIgnoreCase(class_name, "PutSQL")) {
-      return getObjectFactory<minifi::processors::PutSQL>();
-    }
-    if (utils::StringUtils::equalsIgnoreCase(class_name, "QueryDatabaseTable")) {
-      return getObjectFactory<minifi::processors::QueryDatabaseTable>();
-    }
-    if (utils::StringUtils::equalsIgnoreCase(class_name, "ODBCService")) {
-      return getObjectFactory<minifi::sql::controllers::ODBCService>();
-    }
-
-    return nullptr;
-  }
-};
-
-extern "C" {
-  DLL_EXPORT void *createSQLFactory(void);
-}
diff --git a/extensions/sql/processors/ExecuteSQL.cpp b/extensions/sql/processors/ExecuteSQL.cpp
index f8e8acb..4bd0baf 100644
--- a/extensions/sql/processors/ExecuteSQL.cpp
+++ b/extensions/sql/processors/ExecuteSQL.cpp
@@ -29,6 +29,7 @@
 #include "io/StreamPipe.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 #include "Exception.h"
 #include "data/JSONSQLWriter.h"
 #include "data/SQLRowsetProcessor.h"
@@ -121,6 +122,8 @@ void ExecuteSQL::processOnTrigger(core::ProcessContext& context, core::ProcessSe
   }
 }
 
+REGISTER_RESOURCE(ExecuteSQL, "ExecuteSQL to execute SELECT statement via ODBC.");
+
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/sql/processors/ExecuteSQL.h b/extensions/sql/processors/ExecuteSQL.h
index be56837..eb273b5 100644
--- a/extensions/sql/processors/ExecuteSQL.h
+++ b/extensions/sql/processors/ExecuteSQL.h
@@ -22,7 +22,6 @@
 
 #include <string>
 
-#include "core/Resource.h"
 #include "core/ProcessSession.h"
 #include "core/ProcessContext.h"
 #include "SQLProcessor.h"
@@ -40,24 +39,22 @@ class ExecuteSQL : public SQLProcessor, public FlowFileSource {
   explicit ExecuteSQL(const std::string& name, const utils::Identifier& uuid = {});
 
   //! Processor Name
-  static const std::string ProcessorName;
+  EXTENSIONAPI static const std::string ProcessorName;
 
   void processOnSchedule(core::ProcessContext& context) override;
   void processOnTrigger(core::ProcessContext& context, core::ProcessSession& session) override;
 
   void initialize() override;
 
-  static const core::Property SQLSelectQuery;
+  EXTENSIONAPI static const core::Property SQLSelectQuery;
 
-  static const core::Relationship Success;
-  static const core::Relationship Failure;
+  EXTENSIONAPI static const core::Relationship Success;
+  EXTENSIONAPI static const core::Relationship Failure;
 
-  static const std::string RESULT_ROW_COUNT;
-  static const std::string INPUT_FLOW_FILE_UUID;
+  EXTENSIONAPI static const std::string RESULT_ROW_COUNT;
+  EXTENSIONAPI static const std::string INPUT_FLOW_FILE_UUID;
 };
 
-REGISTER_RESOURCE(ExecuteSQL, "ExecuteSQL to execute SELECT statement via ODBC.");
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/sql/processors/FlowFileSource.h b/extensions/sql/processors/FlowFileSource.h
index 8cede63..60ff2e0 100644
--- a/extensions/sql/processors/FlowFileSource.h
+++ b/extensions/sql/processors/FlowFileSource.h
@@ -35,12 +35,12 @@ namespace processors {
 
 class FlowFileSource {
  public:
-  static const std::string FRAGMENT_IDENTIFIER;
-  static const std::string FRAGMENT_COUNT;
-  static const std::string FRAGMENT_INDEX;
+  EXTENSIONAPI static const std::string FRAGMENT_IDENTIFIER;
+  EXTENSIONAPI static const std::string FRAGMENT_COUNT;
+  EXTENSIONAPI static const std::string FRAGMENT_INDEX;
 
-  static const core::Property OutputFormat;
-  static const core::Property MaxRowsPerFlowFile;
+  EXTENSIONAPI static const core::Property OutputFormat;
+  EXTENSIONAPI static const core::Property MaxRowsPerFlowFile;
 
   SMART_ENUM(OutputType,
     (JSON, "JSON"),
diff --git a/extensions/sql/processors/PutSQL.cpp b/extensions/sql/processors/PutSQL.cpp
index ee8b4ce..c4fdfa5 100644
--- a/extensions/sql/processors/PutSQL.cpp
+++ b/extensions/sql/processors/PutSQL.cpp
@@ -30,6 +30,7 @@
 #include "io/StreamPipe.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 #include "Exception.h"
 #include "data/DatabaseConnectors.h"
 #include "data/JSONSQLWriter.h"
@@ -90,6 +91,8 @@ void PutSQL::processOnTrigger(core::ProcessContext& context, core::ProcessSessio
   connection_->prepareStatement(sql_statement)->execute(collectArguments(flow_file));
 }
 
+REGISTER_RESOURCE(PutSQL, "PutSQL to execute SQL command via ODBC.");
+
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/sql/processors/PutSQL.h b/extensions/sql/processors/PutSQL.h
index 6e249d4..4b76db0 100644
--- a/extensions/sql/processors/PutSQL.h
+++ b/extensions/sql/processors/PutSQL.h
@@ -22,7 +22,6 @@
 
 #include <string>
 
-#include "core/Resource.h"
 #include "core/ProcessSession.h"
 #include "SQLProcessor.h"
 
@@ -38,20 +37,18 @@ class PutSQL: public SQLProcessor {
   explicit PutSQL(const std::string& name, const utils::Identifier& uuid = {});
 
   //! Processor Name
-  static const std::string ProcessorName;
+  EXTENSIONAPI static const std::string ProcessorName;
 
   void processOnSchedule(core::ProcessContext& context) override;
   void processOnTrigger(core::ProcessContext& context, core::ProcessSession& session) override;
 
   void initialize() override;
 
-  static const core::Property SQLStatement;
+  EXTENSIONAPI static const core::Property SQLStatement;
 
-  static const core::Relationship Success;
+  EXTENSIONAPI static const core::Relationship Success;
 };
 
-REGISTER_RESOURCE(PutSQL, "PutSQL to execute SQL command via ODBC.");
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/sql/processors/QueryDatabaseTable.cpp b/extensions/sql/processors/QueryDatabaseTable.cpp
index 4cc4efa..766adb7 100644
--- a/extensions/sql/processors/QueryDatabaseTable.cpp
+++ b/extensions/sql/processors/QueryDatabaseTable.cpp
@@ -30,6 +30,7 @@
 #include "io/BufferStream.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 #include "Exception.h"
 #include "data/JSONSQLWriter.h"
 #include "data/SQLRowsetProcessor.h"
@@ -297,6 +298,7 @@ bool QueryDatabaseTable::saveState() {
   return state_manager_->set(state_map);
 }
 
+REGISTER_RESOURCE(QueryDatabaseTable, "QueryDatabaseTable to execute SELECT statement via ODBC.");
 
 }  // namespace processors
 }  // namespace minifi
diff --git a/extensions/sql/processors/QueryDatabaseTable.h b/extensions/sql/processors/QueryDatabaseTable.h
index caecdc0..b496bb6 100644
--- a/extensions/sql/processors/QueryDatabaseTable.h
+++ b/extensions/sql/processors/QueryDatabaseTable.h
@@ -25,7 +25,6 @@
 #include <unordered_map>
 #include <memory>
 
-#include "core/Resource.h"
 #include "core/ProcessSession.h"
 #include "SQLProcessor.h"
 #include "FlowFileSource.h"
@@ -41,23 +40,23 @@ class QueryDatabaseTable: public SQLProcessor, public FlowFileSource {
  public:
   explicit QueryDatabaseTable(const std::string& name, const utils::Identifier& uuid = {});
 
-  static const std::string RESULT_TABLE_NAME;
-  static const std::string RESULT_ROW_COUNT;
+  EXTENSIONAPI static const std::string RESULT_TABLE_NAME;
+  EXTENSIONAPI static const std::string RESULT_ROW_COUNT;
 
-  static const std::string TABLENAME_KEY;
-  static const std::string MAXVALUE_KEY_PREFIX;
+  EXTENSIONAPI static const std::string TABLENAME_KEY;
+  EXTENSIONAPI static const std::string MAXVALUE_KEY_PREFIX;
 
   //! Processor Name
-  static const std::string ProcessorName;
+  EXTENSIONAPI static const std::string ProcessorName;
 
-  static const core::Property TableName;
-  static const core::Property ColumnNames;
-  static const core::Property MaxValueColumnNames;
-  static const core::Property WhereClause;
+  EXTENSIONAPI static const core::Property TableName;
+  EXTENSIONAPI static const core::Property ColumnNames;
+  EXTENSIONAPI static const core::Property MaxValueColumnNames;
+  EXTENSIONAPI static const core::Property WhereClause;
 
-  static const std::string InitialMaxValueDynamicPropertyPrefix;
+  EXTENSIONAPI static const std::string InitialMaxValueDynamicPropertyPrefix;
 
-  static const core::Relationship Success;
+  EXTENSIONAPI static const core::Relationship Success;
 
   bool supportsDynamicProperties() override {
     return true;
@@ -90,8 +89,6 @@ class QueryDatabaseTable: public SQLProcessor, public FlowFileSource {
   std::unordered_map<std::string, std::string> max_values_;
 };
 
-REGISTER_RESOURCE(QueryDatabaseTable, "QueryDatabaseTable to execute SELECT statement via ODBC.");
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/sql/services/DatabaseService.h b/extensions/sql/services/DatabaseService.h
index 4d3decc..78bf55e 100644
--- a/extensions/sql/services/DatabaseService.h
+++ b/extensions/sql/services/DatabaseService.h
@@ -56,7 +56,7 @@ class DatabaseService : public core::controller::ControllerService {
   /**
    * Parameters needed.
    */
-  static core::Property ConnectionString;
+  EXTENSIONAPI static core::Property ConnectionString;
 
   void initialize() override;
 
diff --git a/extensions/sql/services/ODBCConnector.cpp b/extensions/sql/services/ODBCConnector.cpp
index d785bd7..271d951 100644
--- a/extensions/sql/services/ODBCConnector.cpp
+++ b/extensions/sql/services/ODBCConnector.cpp
@@ -22,6 +22,7 @@
 #include <memory>
 #include <set>
 #include "core/Property.h"
+#include "core/Resource.h"
 #include "ODBCConnector.h"
 #include "io/validation.h"
 #include "properties/Configure.h"
@@ -37,6 +38,8 @@ std::unique_ptr<sql::Connection> ODBCService::getConnection() const {
   return std::unique_ptr<sql::Connection>(new ODBCConnection(connection_string_));
 }
 
+REGISTER_RESOURCE(ODBCService, "Controller service that provides ODBC database connection");
+
 } /* namespace controllers */
 } /* namespace sql */
 } /* namespace minifi */
diff --git a/extensions/sql/services/ODBCConnector.h b/extensions/sql/services/ODBCConnector.h
index 5474134..dc66124 100644
--- a/extensions/sql/services/ODBCConnector.h
+++ b/extensions/sql/services/ODBCConnector.h
@@ -22,7 +22,6 @@
 #include "core/controller/ControllerService.h"
 
 #include "DatabaseService.h"
-#include "core/Resource.h"
 #include "data/SociConnectors.h"
 
 namespace org {
@@ -58,8 +57,6 @@ class ODBCService : public DatabaseService {
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(ODBCService, "Controller service that provides ODBC database connection");
-
 } /* namespace controllers */
 } /* namespace sql */
 } /* namespace minifi */
diff --git a/extensions/standard-processors/CMakeLists.txt b/extensions/standard-processors/CMakeLists.txt
index df3e8e8..19fe86a 100644
--- a/extensions/standard-processors/CMakeLists.txt
+++ b/extensions/standard-processors/CMakeLists.txt
@@ -22,8 +22,7 @@ include(${CMAKE_SOURCE_DIR}/extensions/ExtensionHeader.txt)
 
 file(GLOB SOURCES  "processors/*.cpp" "controllers/*.cpp" )
 
-add_library(minifi-standard-processors STATIC ${SOURCES})
-set_property(TARGET minifi-standard-processors PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-standard-processors SHARED ${SOURCES})
 
 include(RangeV3)
 target_link_libraries(minifi-standard-processors ${LIBMINIFI} Threads::Threads range-v3)
diff --git a/extensions/standard-processors/controllers/UnorderedMapKeyValueStoreService.cpp b/extensions/standard-processors/controllers/UnorderedMapKeyValueStoreService.cpp
index 2822421..4a324f2 100644
--- a/extensions/standard-processors/controllers/UnorderedMapKeyValueStoreService.cpp
+++ b/extensions/standard-processors/controllers/UnorderedMapKeyValueStoreService.cpp
@@ -16,6 +16,7 @@
  */
 
 #include "UnorderedMapKeyValueStoreService.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -98,6 +99,8 @@ bool UnorderedMapKeyValueStoreService::update(const std::string& key, const std:
   return true;
 }
 
+REGISTER_RESOURCE(UnorderedMapKeyValueStoreService, "A key-value service implemented by a locked std::unordered_map<std::string, std::string>");
+
 } /* namespace controllers */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/standard-processors/controllers/UnorderedMapKeyValueStoreService.h b/extensions/standard-processors/controllers/UnorderedMapKeyValueStoreService.h
index e1c1d97..8b40b9a 100644
--- a/extensions/standard-processors/controllers/UnorderedMapKeyValueStoreService.h
+++ b/extensions/standard-processors/controllers/UnorderedMapKeyValueStoreService.h
@@ -28,7 +28,6 @@
 #include "properties/Configure.h"
 #include "core/logging/Logger.h"
 #include "core/logging/LoggerConfiguration.h"
-#include "core/Resource.h"
 #include "controllers/keyvalue/PersistableKeyValueStoreService.h"
 
 namespace org {
@@ -69,8 +68,6 @@ class UnorderedMapKeyValueStoreService : virtual public PersistableKeyValueStore
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(UnorderedMapKeyValueStoreService, "A key-value service implemented by a locked std::unordered_map<std::string, std::string>");
-
 }  // namespace controllers
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/controllers/UnorderedMapPersistableKeyValueStoreService.cpp b/extensions/standard-processors/controllers/UnorderedMapPersistableKeyValueStoreService.cpp
index 47565b4..44cfa61 100644
--- a/extensions/standard-processors/controllers/UnorderedMapPersistableKeyValueStoreService.cpp
+++ b/extensions/standard-processors/controllers/UnorderedMapPersistableKeyValueStoreService.cpp
@@ -22,6 +22,7 @@
 
 #include "utils/file/FileUtils.h"
 #include "utils/StringUtils.h"
+#include "core/Resource.h"
 
 namespace {
   std::string escape(const std::string& str) {
@@ -249,6 +250,8 @@ bool UnorderedMapPersistableKeyValueStoreService::load() {
   return true;
 }
 
+REGISTER_RESOURCE(UnorderedMapPersistableKeyValueStoreService, "A persistable key-value service implemented by a locked std::unordered_map<std::string, std::string> and persisted into a file");
+
 }  // namespace controllers
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/controllers/UnorderedMapPersistableKeyValueStoreService.h b/extensions/standard-processors/controllers/UnorderedMapPersistableKeyValueStoreService.h
index a4bf6b7..f25cd33 100644
--- a/extensions/standard-processors/controllers/UnorderedMapPersistableKeyValueStoreService.h
+++ b/extensions/standard-processors/controllers/UnorderedMapPersistableKeyValueStoreService.h
@@ -29,7 +29,6 @@
 #include "properties/Configure.h"
 #include "core/logging/Logger.h"
 #include "core/logging/LoggerConfiguration.h"
-#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -88,7 +87,6 @@ class UnorderedMapPersistableKeyValueStoreService : public AbstractAutoPersistin
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(UnorderedMapPersistableKeyValueStoreService, "A persistable key-value service implemented by a locked std::unordered_map<std::string, std::string> and persisted into a file");
 static_assert(std::is_convertible<UnorderedMapKeyValueStoreService*, PersistableKeyValueStoreService*>::value, "UnorderedMapKeyValueStoreService is a PersistableKeyValueStoreService");
 
 }  // namespace controllers
diff --git a/extensions/standard-processors/processors/AppendHostInfo.cpp b/extensions/standard-processors/processors/AppendHostInfo.cpp
index fed4ad3..e117d1b 100644
--- a/extensions/standard-processors/processors/AppendHostInfo.cpp
+++ b/extensions/standard-processors/processors/AppendHostInfo.cpp
@@ -31,6 +31,7 @@
 #include "core/Property.h"
 #include "core/ProcessSession.h"
 #include "core/FlowFile.h"
+#include "core/Resource.h"
 #include "io/ClientSocket.h"
 #include "utils/NetworkInterfaceInfo.h"
 
@@ -119,6 +120,8 @@ void AppendHostInfo::refreshHostInfo() {
   }
 }
 
+REGISTER_RESOURCE(AppendHostInfo, "Appends host information such as IP address and hostname as an attribute to incoming flowfiles.");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/standard-processors/processors/AppendHostInfo.h b/extensions/standard-processors/processors/AppendHostInfo.h
index 5ccb253..1775be2 100644
--- a/extensions/standard-processors/processors/AppendHostInfo.h
+++ b/extensions/standard-processors/processors/AppendHostInfo.h
@@ -31,8 +31,8 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Core.h"
-#include "core/Resource.h"
 #include "core/logging/LoggerConfiguration.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -53,12 +53,12 @@ class AppendHostInfo : public core::Processor {
   virtual ~AppendHostInfo() = default;
   static constexpr char const* ProcessorName = "AppendHostInfo";
 
-  static core::Property InterfaceNameFilter;
-  static core::Property HostAttribute;
-  static core::Property IPAttribute;
-  static core::Property RefreshPolicy;
+  EXTENSIONAPI static core::Property InterfaceNameFilter;
+  EXTENSIONAPI static core::Property HostAttribute;
+  EXTENSIONAPI static core::Property IPAttribute;
+  EXTENSIONAPI static core::Property RefreshPolicy;
 
-  static core::Relationship Success;
+  EXTENSIONAPI static core::Relationship Success;
 
  public:
   void onSchedule(const std::shared_ptr<core::ProcessContext>& context, const std::shared_ptr<core::ProcessSessionFactory>& sessionFactory) override;
@@ -80,8 +80,6 @@ class AppendHostInfo : public core::Processor {
   std::optional<std::string> ipaddresses_;
 };
 
-REGISTER_RESOURCE(AppendHostInfo, "Appends host information such as IP address and hostname as an attribute to incoming flowfiles.");
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/processors/AttributesToJSON.cpp b/extensions/standard-processors/processors/AttributesToJSON.cpp
index e298905..ec6c0ff 100644
--- a/extensions/standard-processors/processors/AttributesToJSON.cpp
+++ b/extensions/standard-processors/processors/AttributesToJSON.cpp
@@ -25,6 +25,7 @@
 #include "utils/StringUtils.h"
 #include "utils/ProcessorConfigUtils.h"
 #include "range/v3/algorithm/find.hpp"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -171,6 +172,9 @@ void AttributesToJSON::onTrigger(core::ProcessContext* /*context*/, core::Proces
   }
 }
 
+REGISTER_RESOURCE(AttributesToJSON, "Generates a JSON representation of the input FlowFile Attributes. "
+  "The resulting JSON can be written to either a new Attribute 'JSONAttributes' or written to the FlowFile as content.");
+
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/processors/AttributesToJSON.h b/extensions/standard-processors/processors/AttributesToJSON.h
index d2370f9..b1ea1d1 100644
--- a/extensions/standard-processors/processors/AttributesToJSON.h
+++ b/extensions/standard-processors/processors/AttributesToJSON.h
@@ -32,6 +32,7 @@
 #include "core/Property.h"
 #include "core/logging/Logger.h"
 #include "utils/Enum.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -42,14 +43,14 @@ namespace processors {
 class AttributesToJSON : public core::Processor {
  public:
   // Supported Properties
-  static const core::Property AttributesList;
-  static const core::Property AttributesRegularExpression;
-  static const core::Property Destination;
-  static const core::Property IncludeCoreAttributes;
-  static const core::Property NullValue;
+  EXTENSIONAPI static const core::Property AttributesList;
+  EXTENSIONAPI static const core::Property AttributesRegularExpression;
+  EXTENSIONAPI static const core::Property Destination;
+  EXTENSIONAPI static const core::Property IncludeCoreAttributes;
+  EXTENSIONAPI static const core::Property NullValue;
 
   // Supported Relationships
-  static const core::Relationship Success;
+  EXTENSIONAPI static const core::Relationship Success;
 
   SMART_ENUM(WriteDestination,
     (FLOWFILE_ATTRIBUTE, "flowfile-attribute"),
@@ -94,9 +95,6 @@ class AttributesToJSON : public core::Processor {
   bool null_value_ = false;
 };
 
-REGISTER_RESOURCE(AttributesToJSON, "Generates a JSON representation of the input FlowFile Attributes. "
-  "The resulting JSON can be written to either a new Attribute 'JSONAttributes' or written to the FlowFile as content.");
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/processors/ExecuteProcess.cpp b/extensions/standard-processors/processors/ExecuteProcess.cpp
index 902d369..2dabc6e 100644
--- a/extensions/standard-processors/processors/ExecuteProcess.cpp
+++ b/extensions/standard-processors/processors/ExecuteProcess.cpp
@@ -24,6 +24,7 @@
 #include <set>
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 #include "utils/StringUtils.h"
 #include "utils/TimeUtil.h"
 #include "core/TypedValues.h"
@@ -239,6 +240,11 @@ void ExecuteProcess::onTrigger(core::ProcessContext *context, core::ProcessSessi
     }
   }
 }
+
+REGISTER_RESOURCE(ExecuteProcess, "Runs an operating system command specified by the user and writes the output of that command to a FlowFile. If the command is expected to be long-running,"
+                  "the Processor can output the partial data on a specified interval. When this option is used, the output is expected to be in textual format,"
+                  "as it typically does not make sense to split binary data on arbitrary time-based intervals.");
+
 #endif
 } /* namespace processors */
 } /* namespace minifi */
diff --git a/extensions/standard-processors/processors/ExecuteProcess.h b/extensions/standard-processors/processors/ExecuteProcess.h
index c9e5b1b..517bed1 100644
--- a/extensions/standard-processors/processors/ExecuteProcess.h
+++ b/extensions/standard-processors/processors/ExecuteProcess.h
@@ -39,7 +39,6 @@
 #include "core/logging/LoggerConfiguration.h"
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
-#include "core/Resource.h"
 #include "FlowFileRecord.h"
 #include "io/BaseStream.h"
 #include "utils/gsl.h"
@@ -123,9 +122,6 @@ class ExecuteProcess : public core::Processor {
   pid_t _pid;
 };
 
-REGISTER_RESOURCE(ExecuteProcess, "Runs an operating system command specified by the user and writes the output of that command to a FlowFile. If the command is expected to be long-running,"
-                  "the Processor can output the partial data on a specified interval. When this option is used, the output is expected to be in textual format,"
-                  "as it typically does not make sense to split binary data on arbitrary time-based intervals.");
 #endif
 }  // namespace processors
 }  // namespace minifi
diff --git a/extensions/standard-processors/processors/ExtractText.cpp b/extensions/standard-processors/processors/ExtractText.cpp
index f800e00..30aa277 100644
--- a/extensions/standard-processors/processors/ExtractText.cpp
+++ b/extensions/standard-processors/processors/ExtractText.cpp
@@ -31,6 +31,7 @@
 #include "ExtractText.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 #include "core/FlowFile.h"
 #include "utils/gsl.h"
 
@@ -221,6 +222,8 @@ ExtractText::ReadCallback::ReadCallback(std::shared_ptr<core::FlowFile> flowFile
   buffer_.resize(std::min(gsl::narrow<size_t>(flowFile_->getSize()), MAX_BUFFER_SIZE));
 }
 
+REGISTER_RESOURCE(ExtractText, "Extracts the content of a FlowFile and places it into an attribute.");
+
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/processors/ExtractText.h b/extensions/standard-processors/processors/ExtractText.h
index 64c2d5f..b9cf78e 100644
--- a/extensions/standard-processors/processors/ExtractText.h
+++ b/extensions/standard-processors/processors/ExtractText.h
@@ -26,8 +26,8 @@
 
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
-#include "core/Resource.h"
 #include "FlowFileRecord.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -47,21 +47,21 @@ class ExtractText : public core::Processor {
         logger_ = logging::LoggerFactory<ExtractText>::getLogger();
     }
     //! Processor Name
-    static constexpr char const* ProcessorName = "ExtractText";
+    EXTENSIONAPI static constexpr char const* ProcessorName = "ExtractText";
     //! Supported Properties
-    static core::Property Attribute;
-    static core::Property SizeLimit;
+    EXTENSIONAPI static core::Property Attribute;
+    EXTENSIONAPI static core::Property SizeLimit;
 
-    static core::Property RegexMode;
-    static core::Property IgnoreCaptureGroupZero;
-    static core::Property InsensitiveMatch;
-    static core::Property MaxCaptureGroupLen;
-    static core::Property EnableRepeatingCaptureGroup;
+    EXTENSIONAPI static core::Property RegexMode;
+    EXTENSIONAPI static core::Property IgnoreCaptureGroupZero;
+    EXTENSIONAPI static core::Property InsensitiveMatch;
+    EXTENSIONAPI static core::Property MaxCaptureGroupLen;
+    EXTENSIONAPI static core::Property EnableRepeatingCaptureGroup;
 
     //! Supported Relationships
-    static core::Relationship Success;
+    EXTENSIONAPI static core::Relationship Success;
     //! Default maximum bytes to read into an attribute
-    static constexpr int DEFAULT_SIZE_LIMIT = 2 * 1024 * 1024;
+    EXTENSIONAPI static constexpr int DEFAULT_SIZE_LIMIT = 2 * 1024 * 1024;
 
     //! OnTrigger method, implemented by NiFi ExtractText
     void onTrigger(core::ProcessContext *context, core::ProcessSession *session) override;
@@ -94,8 +94,6 @@ class ExtractText : public core::Processor {
     std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(ExtractText, "Extracts the content of a FlowFile and places it into an attribute.");
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/processors/GenerateFlowFile.cpp b/extensions/standard-processors/processors/GenerateFlowFile.cpp
index 58cc738..654e5ff 100644
--- a/extensions/standard-processors/processors/GenerateFlowFile.cpp
+++ b/extensions/standard-processors/processors/GenerateFlowFile.cpp
@@ -40,6 +40,7 @@
 #include "core/ProcessSession.h"
 #include "core/PropertyValidation.h"
 #include "core/TypedValues.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -158,6 +159,8 @@ void GenerateFlowFile::onTrigger(core::ProcessContext* /*context*/, core::Proces
   }
 }
 
+REGISTER_RESOURCE(GenerateFlowFile, "This processor creates FlowFiles with random data or custom content. GenerateFlowFile is useful for load testing, configuration, and simulation.");
+
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/processors/GenerateFlowFile.h b/extensions/standard-processors/processors/GenerateFlowFile.h
index 37b2bbb..ed77bd0 100644
--- a/extensions/standard-processors/processors/GenerateFlowFile.h
+++ b/extensions/standard-processors/processors/GenerateFlowFile.h
@@ -29,8 +29,8 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Core.h"
-#include "core/Resource.h"
 #include "utils/gsl.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -54,16 +54,16 @@ class GenerateFlowFile : public core::Processor {
   // Destructor
   ~GenerateFlowFile() override = default;
   // Processor Name
-  static constexpr char const* ProcessorName = "GenerateFlowFile";
+  EXTENSIONAPI static constexpr char const* ProcessorName = "GenerateFlowFile";
   // Supported Properties
-  static core::Property FileSize;
-  static core::Property BatchSize;
-  static core::Property DataFormat;
-  static core::Property UniqueFlowFiles;
-  static core::Property CustomText;
-  static const char *DATA_FORMAT_TEXT;
+  EXTENSIONAPI static core::Property FileSize;
+  EXTENSIONAPI static core::Property BatchSize;
+  EXTENSIONAPI static core::Property DataFormat;
+  EXTENSIONAPI static core::Property UniqueFlowFiles;
+  EXTENSIONAPI static core::Property CustomText;
+  EXTENSIONAPI static const char *DATA_FORMAT_TEXT;
   // Supported Relationships
-  static core::Relationship Success;
+  EXTENSIONAPI static core::Relationship Success;
   // Nest Callback Class for write stream
   class WriteCallback : public OutputStreamCallback {
    public:
@@ -102,8 +102,6 @@ class GenerateFlowFile : public core::Processor {
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(GenerateFlowFile, "This processor creates FlowFiles with random data or custom content. GenerateFlowFile is useful for load testing, configuration, and simulation.");
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/processors/GetFile.cpp b/extensions/standard-processors/processors/GetFile.cpp
index 44065da..446dcec 100644
--- a/extensions/standard-processors/processors/GetFile.cpp
+++ b/extensions/standard-processors/processors/GetFile.cpp
@@ -34,6 +34,7 @@
 #include "utils/TimeUtil.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 #include "core/TypedValues.h"
 #include "utils/FileReaderCallback.h"
 
@@ -284,6 +285,8 @@ int16_t GetFile::getMetricNodes(std::vector<std::shared_ptr<state::response::Res
   return 0;
 }
 
+REGISTER_RESOURCE(GetFile, "Creates FlowFiles from files in a directory. MiNiFi will ignore files for which it doesn't have read permissions.");
+
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/processors/GetFile.h b/extensions/standard-processors/processors/GetFile.h
index aec7e5c..122d939 100644
--- a/extensions/standard-processors/processors/GetFile.h
+++ b/extensions/standard-processors/processors/GetFile.h
@@ -29,8 +29,8 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Core.h"
-#include "core/Resource.h"
 #include "core/logging/LoggerConfiguration.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -121,21 +121,21 @@ class GetFile : public core::Processor, public state::response::MetricsNodeSourc
   ~GetFile() override = default;
 
   // Processor Name
-  static constexpr char const* ProcessorName = "GetFile";
+  EXTENSIONAPI static constexpr char const* ProcessorName = "GetFile";
   // Supported Properties
-  static core::Property Directory;
-  static core::Property Recurse;
-  static core::Property KeepSourceFile;
-  static core::Property MinAge;
-  static core::Property MaxAge;
-  static core::Property MinSize;
-  static core::Property MaxSize;
-  static core::Property IgnoreHiddenFile;
-  static core::Property PollInterval;
-  static core::Property BatchSize;
-  static core::Property FileFilter;
+  EXTENSIONAPI static core::Property Directory;
+  EXTENSIONAPI static core::Property Recurse;
+  EXTENSIONAPI static core::Property KeepSourceFile;
+  EXTENSIONAPI static core::Property MinAge;
+  EXTENSIONAPI static core::Property MaxAge;
+  EXTENSIONAPI static core::Property MinSize;
+  EXTENSIONAPI static core::Property MaxSize;
+  EXTENSIONAPI static core::Property IgnoreHiddenFile;
+  EXTENSIONAPI static core::Property PollInterval;
+  EXTENSIONAPI static core::Property BatchSize;
+  EXTENSIONAPI static core::Property FileFilter;
   // Supported Relationships
-  static core::Relationship Success;
+  EXTENSIONAPI static core::Relationship Success;
 
  public:
   /**
@@ -181,8 +181,6 @@ class GetFile : public core::Processor, public state::response::MetricsNodeSourc
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(GetFile, "Creates FlowFiles from files in a directory. MiNiFi will ignore files for which it doesn't have read permissions.");
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/processors/GetTCP.cpp b/extensions/standard-processors/processors/GetTCP.cpp
index 1c93a8e..78e0339 100644
--- a/extensions/standard-processors/processors/GetTCP.cpp
+++ b/extensions/standard-processors/processors/GetTCP.cpp
@@ -36,6 +36,7 @@
 #include "utils/TimeUtil.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -314,6 +315,8 @@ int16_t GetTCP::getMetricNodes(std::vector<std::shared_ptr<state::response::Resp
   return 0;
 }
 
+REGISTER_RESOURCE(GetTCP, "Establishes a TCP Server that defines and retrieves one or more byte messages from clients");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/standard-processors/processors/GetTCP.h b/extensions/standard-processors/processors/GetTCP.h
index 7595763..4daa4ee 100644
--- a/extensions/standard-processors/processors/GetTCP.h
+++ b/extensions/standard-processors/processors/GetTCP.h
@@ -30,12 +30,12 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Core.h"
-#include "core/Resource.h"
 #include "concurrentqueue.h"
 #include "utils/ThreadPool.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "controllers/SSLContextService.h"
 #include "utils/gsl.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -189,21 +189,21 @@ class GetTCP : public core::Processor, public state::response::MetricsNodeSource
 // Destructor
   ~GetTCP() override = default;
 // Processor Name
-  static constexpr char const* ProcessorName = "GetTCP";
+  EXTENSIONAPI static constexpr char const* ProcessorName = "GetTCP";
 
   // Supported Properties
-  static core::Property EndpointList;
-  static core::Property ConcurrentHandlers;
-  static core::Property ReconnectInterval;
-  static core::Property StayConnected;
-  static core::Property ReceiveBufferSize;
-  static core::Property SSLContextService;
-  static core::Property ConnectionAttemptLimit;
-  static core::Property EndOfMessageByte;
+  EXTENSIONAPI static core::Property EndpointList;
+  EXTENSIONAPI static core::Property ConcurrentHandlers;
+  EXTENSIONAPI static core::Property ReconnectInterval;
+  EXTENSIONAPI static core::Property StayConnected;
+  EXTENSIONAPI static core::Property ReceiveBufferSize;
+  EXTENSIONAPI static core::Property SSLContextService;
+  EXTENSIONAPI static core::Property ConnectionAttemptLimit;
+  EXTENSIONAPI static core::Property EndOfMessageByte;
 
   // Supported Relationships
-  static core::Relationship Success;
-  static core::Relationship Partial;
+  EXTENSIONAPI static core::Relationship Success;
+  EXTENSIONAPI static core::Relationship Partial;
 
  public:
   /**
@@ -277,9 +277,6 @@ class GetTCP : public core::Processor, public state::response::MetricsNodeSource
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(GetTCP, "Establishes a TCP Server that defines and retrieves one or more byte messages from clients");
-
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/processors/HashContent.cpp b/extensions/standard-processors/processors/HashContent.cpp
index 0898826..f2237a3 100644
--- a/extensions/standard-processors/processors/HashContent.cpp
+++ b/extensions/standard-processors/processors/HashContent.cpp
@@ -30,6 +30,7 @@
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
 #include "core/FlowFile.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -112,6 +113,8 @@ HashContent::ReadCallback::ReadCallback(std::shared_ptr<core::FlowFile> flowFile
     parent_(parent)
   {}
 
+REGISTER_RESOURCE(HashContent,"HashContent calculates the checksum of the content of the flowfile and adds it as an attribute. Configuration options exist to select hashing algorithm and set the name of the attribute."); // NOLINT
+
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/processors/HashContent.h b/extensions/standard-processors/processors/HashContent.h
index 8522593..8b6ebe2 100644
--- a/extensions/standard-processors/processors/HashContent.h
+++ b/extensions/standard-processors/processors/HashContent.h
@@ -37,9 +37,9 @@
 #include "FlowFileRecord.h"
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
-#include "core/Resource.h"
 #include "io/BaseStream.h"
 #include "utils/StringUtils.h"
+#include "utils/Export.h"
 
 using HashReturnType = std::pair<std::string, int64_t>;
 
@@ -142,14 +142,14 @@ class HashContent : public core::Processor {
     logger_ = logging::LoggerFactory<HashContent>::getLogger();
   }
   //! Processor Name
-  static constexpr char const* ProcessorName = "HashContent";
+  EXTENSIONAPI static constexpr char const* ProcessorName = "HashContent";
   //! Supported Properties
-  static core::Property HashAttribute;
-  static core::Property HashAlgorithm;
-  static core::Property FailOnEmpty;
+  EXTENSIONAPI static core::Property HashAttribute;
+  EXTENSIONAPI static core::Property HashAlgorithm;
+  EXTENSIONAPI static core::Property FailOnEmpty;
   //! Supported Relationships
-  static core::Relationship Success;
-  static core::Relationship Failure;
+  EXTENSIONAPI static core::Relationship Success;
+  EXTENSIONAPI static core::Relationship Failure;
 
   void onSchedule(core::ProcessContext *context, core::ProcessSessionFactory *sessionFactory) override;
 
@@ -181,8 +181,6 @@ class HashContent : public core::Processor {
   bool failOnEmpty_;
 };
 
-REGISTER_RESOURCE(HashContent,"HashContent calculates the checksum of the content of the flowfile and adds it as an attribute. Configuration options exist to select hashing algorithm and set the name of the attribute."); // NOLINT
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/processors/ListenSyslog.cpp b/extensions/standard-processors/processors/ListenSyslog.cpp
index 23abb24..aff4ef5 100644
--- a/extensions/standard-processors/processors/ListenSyslog.cpp
+++ b/extensions/standard-processors/processors/ListenSyslog.cpp
@@ -29,6 +29,7 @@
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
 #include "core/TypedValues.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -317,6 +318,14 @@ void ListenSyslog::onTrigger(core::ProcessContext *context, core::ProcessSession
   flowFile->addAttribute("syslog.port", std::to_string(_port));
   session->transfer(flowFile, Success);
 }
+
+REGISTER_RESOURCE(ListenSyslog, "Listens for Syslog messages being sent to a given port over TCP or UDP. Incoming messages are checked against regular expressions for RFC5424 and RFC3164 formatted messages. " // NOLINT
+                  "The format of each message is: (<PRIORITY>)(VERSION )(TIMESTAMP) (HOSTNAME) (BODY) where version is optional. The timestamp can be an RFC5424 timestamp with a format of "
+                  "\"yyyy-MM-dd'T'HH:mm:ss.SZ\" or \"yyyy-MM-dd'T'HH:mm:ss.S+hh:mm\", or it can be an RFC3164 timestamp with a format of \"MMM d HH:mm:ss\". If an incoming messages matches "
+                  "one of these patterns, the message will be parsed and the individual pieces will be placed in FlowFile attributes, with the original message in the content of the FlowFile. "
+                  "If an incoming message does not match one of these patterns it will not be parsed and the syslog.valid attribute will be set to false with the original message in the content "
+                  "of the FlowFile. Valid messages will be transferred on the success relationship, and invalid messages will be transferred on the invalid relationship.");
+
 #endif
 } /* namespace processors */
 } /* namespace minifi */
diff --git a/extensions/standard-processors/processors/ListenSyslog.h b/extensions/standard-processors/processors/ListenSyslog.h
index b986730..8f6375d 100644
--- a/extensions/standard-processors/processors/ListenSyslog.h
+++ b/extensions/standard-processors/processors/ListenSyslog.h
@@ -48,7 +48,6 @@
 #include "core/logging/LoggerConfiguration.h"
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
-#include "core/Resource.h"
 #include "FlowFileRecord.h"
 #include "utils/gsl.h"
 
@@ -224,13 +223,6 @@ class ListenSyslog : public core::Processor {
   char _buffer[2048];
 };
 
-REGISTER_RESOURCE(ListenSyslog, "Listens for Syslog messages being sent to a given port over TCP or UDP. Incoming messages are checked against regular expressions for RFC5424 and RFC3164 formatted messages. " // NOLINT
-                  "The format of each message is: (<PRIORITY>)(VERSION )(TIMESTAMP) (HOSTNAME) (BODY) where version is optional. The timestamp can be an RFC5424 timestamp with a format of "
-                  "\"yyyy-MM-dd'T'HH:mm:ss.SZ\" or \"yyyy-MM-dd'T'HH:mm:ss.S+hh:mm\", or it can be an RFC3164 timestamp with a format of \"MMM d HH:mm:ss\". If an incoming messages matches "
-                  "one of these patterns, the message will be parsed and the individual pieces will be placed in FlowFile attributes, with the original message in the content of the FlowFile. "
-                  "If an incoming message does not match one of these patterns it will not be parsed and the syslog.valid attribute will be set to false with the original message in the content "
-                  "of the FlowFile. Valid messages will be transferred on the success relationship, and invalid messages will be transferred on the invalid relationship.");
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/processors/LogAttribute.cpp b/extensions/standard-processors/processors/LogAttribute.cpp
index 3a61c8b..8d041b8 100644
--- a/extensions/standard-processors/processors/LogAttribute.cpp
+++ b/extensions/standard-processors/processors/LogAttribute.cpp
@@ -32,6 +32,7 @@
 #include "utils/StringUtils.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -190,6 +191,8 @@ void LogAttribute::onTrigger(const std::shared_ptr<core::ProcessContext> &contex
   logger_->log_debug("Logged %d flow files", i);
 }
 
+REGISTER_RESOURCE(LogAttribute, "Logs attributes of flow files in the MiNiFi application log.");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/standard-processors/processors/LogAttribute.h b/extensions/standard-processors/processors/LogAttribute.h
index ff886d0..5cd5c82 100644
--- a/extensions/standard-processors/processors/LogAttribute.h
+++ b/extensions/standard-processors/processors/LogAttribute.h
@@ -29,9 +29,9 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Core.h"
-#include "core/Resource.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "utils/gsl.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -56,18 +56,18 @@ class LogAttribute : public core::Processor {
   // Destructor
   ~LogAttribute() override = default;
   // Processor Name
-  static constexpr char const* ProcessorName = "LogAttribute";
+  EXTENSIONAPI static constexpr char const* ProcessorName = "LogAttribute";
   // Supported Properties
-  static core::Property LogLevel;
-  static core::Property AttributesToLog;
-  static core::Property AttributesToIgnore;
-  static core::Property LogPayload;
-  static core::Property HexencodePayload;
-  static core::Property MaxPayloadLineLength;
-  static core::Property LogPrefix;
-  static core::Property FlowFilesToLog;
+  EXTENSIONAPI static core::Property LogLevel;
+  EXTENSIONAPI static core::Property AttributesToLog;
+  EXTENSIONAPI static core::Property AttributesToIgnore;
+  EXTENSIONAPI static core::Property LogPayload;
+  EXTENSIONAPI static core::Property HexencodePayload;
+  EXTENSIONAPI static core::Property MaxPayloadLineLength;
+  EXTENSIONAPI static core::Property LogPrefix;
+  EXTENSIONAPI static core::Property FlowFilesToLog;
   // Supported Relationships
-  static core::Relationship Success;
+  EXTENSIONAPI static core::Relationship Success;
   enum LogAttrLevel {
     LogAttrLevelTrace,
     LogAttrLevelDebug,
@@ -135,8 +135,6 @@ class LogAttribute : public core::Processor {
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(LogAttribute, "Logs attributes of flow files in the MiNiFi application log.");
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/processors/PutFile.cpp b/extensions/standard-processors/processors/PutFile.cpp
index 9efae99..1728bd2 100644
--- a/extensions/standard-processors/processors/PutFile.cpp
+++ b/extensions/standard-processors/processors/PutFile.cpp
@@ -31,6 +31,7 @@
 #endif
 #include "utils/file/FileUtils.h"
 #include "utils/gsl.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -364,6 +365,8 @@ PutFile::ReadCallback::~ReadCallback() {
   std::remove(tmp_file_.c_str());
 }
 
+REGISTER_RESOURCE(PutFile, "Writes the contents of a FlowFile to the local file system");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/standard-processors/processors/PutFile.h b/extensions/standard-processors/processors/PutFile.h
index 47509e2..cbef1da 100644
--- a/extensions/standard-processors/processors/PutFile.h
+++ b/extensions/standard-processors/processors/PutFile.h
@@ -28,9 +28,9 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Core.h"
-#include "core/Resource.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "utils/Id.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -57,17 +57,17 @@ class PutFile : public core::Processor {
   ~PutFile() override = default;
 
   // Supported Properties
-  static core::Property Directory;
-  static core::Property ConflictResolution;
-  static core::Property CreateDirs;
-  static core::Property MaxDestFiles;
+  EXTENSIONAPI static core::Property Directory;
+  EXTENSIONAPI static core::Property ConflictResolution;
+  EXTENSIONAPI static core::Property CreateDirs;
+  EXTENSIONAPI static core::Property MaxDestFiles;
 #ifndef WIN32
-  static core::Property Permissions;
-  static core::Property DirectoryPermissions;
+  EXTENSIONAPI static core::Property Permissions;
+  EXTENSIONAPI static core::Property DirectoryPermissions;
 #endif
   // Supported Relationships
-  static core::Relationship Success;
-  static core::Relationship Failure;
+  EXTENSIONAPI static core::Relationship Success;
+  EXTENSIONAPI static core::Relationship Failure;
 
   /**
    * Function that's executed when the processor is scheduled.
@@ -136,8 +136,6 @@ class PutFile : public core::Processor {
 #endif
 };
 
-REGISTER_RESOURCE(PutFile, "Writes the contents of a FlowFile to the local file system");
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/processors/RetryFlowFile.cpp b/extensions/standard-processors/processors/RetryFlowFile.cpp
index 1169c2e..98df049 100644
--- a/extensions/standard-processors/processors/RetryFlowFile.cpp
+++ b/extensions/standard-processors/processors/RetryFlowFile.cpp
@@ -19,6 +19,7 @@
 #include "RetryFlowFile.h"
 
 #include "core/PropertyValidation.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -181,6 +182,15 @@ void RetryFlowFile::setRetriesExceededAttributesOnFlowFile(core::ProcessContext*
   }
 }
 
+REGISTER_RESOURCE(RetryFlowFile,
+    "FlowFiles passed to this Processor have a 'Retry Attribute' value checked against a configured 'Maximum Retries' value. "
+    "If the current attribute value is below the configured maximum, the FlowFile is passed to a retry relationship. "
+    "The FlowFile may or may not be penalized in that condition. If the FlowFile's attribute value exceeds the configured maximum, "
+    "the FlowFile will be passed to a 'retries_exceeded' relationship. "
+    "WARNING: If the incoming FlowFile has a non-numeric value in the configured 'Retry Attribute' attribute, it will be reset to '1'. "
+    "You may choose to fail the FlowFile instead of performing the reset. Additional dynamic properties can be defined for any attributes "
+    "you wish to add to the FlowFiles transferred to 'retries_exceeded'. These attributes support attribute expression language.");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/standard-processors/processors/RetryFlowFile.h b/extensions/standard-processors/processors/RetryFlowFile.h
index 62daa3d..a8e2067 100644
--- a/extensions/standard-processors/processors/RetryFlowFile.h
+++ b/extensions/standard-processors/processors/RetryFlowFile.h
@@ -31,8 +31,9 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Core.h"
-#include "core/Resource.h"
 #include "core/logging/LoggerConfiguration.h"
+#include "utils/OptionalUtils.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -48,21 +49,21 @@ class RetryFlowFile : public core::Processor {
   // Destructor
   virtual ~RetryFlowFile() = default;
   // Processor Name
-  static constexpr char const* ProcessorName = "RetryFlowFile";
+  EXTENSIONAPI static constexpr char const* ProcessorName = "RetryFlowFile";
   // Supported Properties
-  static core::Property RetryAttribute;
-  static core::Property MaximumRetries;
-  static core::Property PenalizeRetries;
-  static core::Property FailOnNonNumericalOverwrite;
-  static core::Property ReuseMode;
+  EXTENSIONAPI static core::Property RetryAttribute;
+  EXTENSIONAPI static core::Property MaximumRetries;
+  EXTENSIONAPI static core::Property PenalizeRetries;
+  EXTENSIONAPI static core::Property FailOnNonNumericalOverwrite;
+  EXTENSIONAPI static core::Property ReuseMode;
   // Supported Relationships
-  static core::Relationship Retry;
-  static core::Relationship RetriesExceeded;
-  static core::Relationship Failure;
+  EXTENSIONAPI static core::Relationship Retry;
+  EXTENSIONAPI static core::Relationship RetriesExceeded;
+  EXTENSIONAPI static core::Relationship Failure;
   // ReuseMode allowable values
-  static constexpr char const* FAIL_ON_REUSE = "Fail on Reuse";
-  static constexpr char const* WARN_ON_REUSE = "Warn on Reuse";
-  static constexpr char const*   RESET_REUSE = "Reset Reuse";
+  EXTENSIONAPI static constexpr char const* FAIL_ON_REUSE = "Fail on Reuse";
+  EXTENSIONAPI static constexpr char const* WARN_ON_REUSE = "Warn on Reuse";
+  EXTENSIONAPI static constexpr char const*   RESET_REUSE = "Reset Reuse";
 
  public:
   bool supportsDynamicProperties() override {
@@ -105,15 +106,6 @@ class RetryFlowFile : public core::Processor {
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(RetryFlowFile,
-    "FlowFiles passed to this Processor have a 'Retry Attribute' value checked against a configured 'Maximum Retries' value. "
-    "If the current attribute value is below the configured maximum, the FlowFile is passed to a retry relationship. "
-    "The FlowFile may or may not be penalized in that condition. If the FlowFile's attribute value exceeds the configured maximum, "
-    "the FlowFile will be passed to a 'retries_exceeded' relationship. "
-    "WARNING: If the incoming FlowFile has a non-numeric value in the configured 'Retry Attribute' attribute, it will be reset to '1'. "
-    "You may choose to fail the FlowFile instead of performing the reset. Additional dynamic properties can be defined for any attributes "
-    "you wish to add to the FlowFiles transferred to 'retries_exceeded'. These attributes support attribute expression language.");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/standard-processors/processors/RouteOnAttribute.cpp b/extensions/standard-processors/processors/RouteOnAttribute.cpp
index efa0956..e97d02a 100644
--- a/extensions/standard-processors/processors/RouteOnAttribute.cpp
+++ b/extensions/standard-processors/processors/RouteOnAttribute.cpp
@@ -24,6 +24,8 @@
 #include <string>
 #include <set>
 
+#include "core/Resource.h"
+
 namespace org {
 namespace apache {
 namespace nifi {
@@ -95,6 +97,8 @@ void RouteOnAttribute::onTrigger(core::ProcessContext *context, core::ProcessSes
   }
 }
 
+REGISTER_RESOURCE(RouteOnAttribute, "Routes FlowFiles based on their Attributes using the Attribute Expression Language.");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/standard-processors/processors/RouteOnAttribute.h b/extensions/standard-processors/processors/RouteOnAttribute.h
index 6cd437a..869249b 100644
--- a/extensions/standard-processors/processors/RouteOnAttribute.h
+++ b/extensions/standard-processors/processors/RouteOnAttribute.h
@@ -28,7 +28,6 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Core.h"
-#include "core/Resource.h"
 #include "core/logging/LoggerConfiguration.h"
 
 namespace org {
@@ -77,8 +76,6 @@ class RouteOnAttribute : public core::Processor {
   std::map<std::string, core::Relationship> route_rels_;
 };
 
-REGISTER_RESOURCE(RouteOnAttribute, "Routes FlowFiles based on their Attributes using the Attribute Expression Language.");
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/processors/TailFile.cpp b/extensions/standard-processors/processors/TailFile.cpp
index 828e425..1dec544 100644
--- a/extensions/standard-processors/processors/TailFile.cpp
+++ b/extensions/standard-processors/processors/TailFile.cpp
@@ -44,6 +44,7 @@
 #include "TailFile.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -855,6 +856,13 @@ std::chrono::milliseconds TailFile::getLookupFrequency() const {
   return lookup_frequency_;
 }
 
+REGISTER_RESOURCE(TailFile, "\"Tails\" a file, or a list of files, ingesting data from the file as it is written to the file. The file is expected to be textual."
+                  " Data is ingested only when a new line is encountered (carriage return or new-line character or combination). If the file to tail is periodically \"rolled over\","
+                  " as is generally the case with log files, an optional Rolling Filename Pattern can be used to retrieve data from files that have rolled over, even if the rollover"
+                  " occurred while NiFi was not running (provided that the data still exists upon restart of NiFi). It is generally advisable to set the Run Schedule to a few seconds,"
+                  " rather than running with the default value of 0 secs, as this Processor will consume a lot of resources if scheduled very aggressively. At this time, this Processor"
+                  " does not support ingesting files that have been compressed when 'rolled over'.");
+
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/processors/TailFile.h b/extensions/standard-processors/processors/TailFile.h
index 5a114d3..4d85505 100644
--- a/extensions/standard-processors/processors/TailFile.h
+++ b/extensions/standard-processors/processors/TailFile.h
@@ -31,9 +31,9 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Core.h"
-#include "core/Resource.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "utils/Enum.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -89,21 +89,21 @@ class TailFile : public core::Processor {
   ~TailFile() override = default;
 
   // Processor Name
-  static constexpr char const* ProcessorName = "TailFile";
+  EXTENSIONAPI static constexpr char const* ProcessorName = "TailFile";
 
   // Supported Properties
-  static core::Property FileName;
-  static core::Property StateFile;
-  static core::Property Delimiter;
-  static core::Property TailMode;
-  static core::Property BaseDirectory;
-  static core::Property RecursiveLookup;
-  static core::Property LookupFrequency;
-  static core::Property RollingFilenamePattern;
-  static core::Property InitialStartPosition;
+  EXTENSIONAPI static core::Property FileName;
+  EXTENSIONAPI static core::Property StateFile;
+  EXTENSIONAPI static core::Property Delimiter;
+  EXTENSIONAPI static core::Property TailMode;
+  EXTENSIONAPI static core::Property BaseDirectory;
+  EXTENSIONAPI static core::Property RecursiveLookup;
+  EXTENSIONAPI static core::Property LookupFrequency;
+  EXTENSIONAPI static core::Property RollingFilenamePattern;
+  EXTENSIONAPI static core::Property InitialStartPosition;
 
   // Supported Relationships
-  static core::Relationship Success;
+  EXTENSIONAPI static core::Relationship Success;
 
   /**
    * Function that's executed when the processor is scheduled.
@@ -186,13 +186,6 @@ class TailFile : public core::Processor {
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(TailFile, "\"Tails\" a file, or a list of files, ingesting data from the file as it is written to the file. The file is expected to be textual."
-                  " Data is ingested only when a new line is encountered (carriage return or new-line character or combination). If the file to tail is periodically \"rolled over\","
-                  " as is generally the case with log files, an optional Rolling Filename Pattern can be used to retrieve data from files that have rolled over, even if the rollover"
-                  " occurred while NiFi was not running (provided that the data still exists upon restart of NiFi). It is generally advisable to set the Run Schedule to a few seconds,"
-                  " rather than running with the default value of 0 secs, as this Processor will consume a lot of resources if scheduled very aggressively. At this time, this Processor"
-                  " does not support ingesting files that have been compressed when 'rolled over'.");
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/processors/UpdateAttribute.cpp b/extensions/standard-processors/processors/UpdateAttribute.cpp
index e717dd5..fa05f44 100644
--- a/extensions/standard-processors/processors/UpdateAttribute.cpp
+++ b/extensions/standard-processors/processors/UpdateAttribute.cpp
@@ -24,6 +24,8 @@
 #include <string>
 #include <set>
 
+#include "core/Resource.h"
+
 namespace org {
 namespace apache {
 namespace nifi {
@@ -77,6 +79,9 @@ void UpdateAttribute::onTrigger(core::ProcessContext *context, core::ProcessSess
   }
 }
 
+REGISTER_RESOURCE(UpdateAttribute, "This processor updates the attributes of a FlowFile using properties that are added by the user. "
+  "This allows you to set default attribute changes that affect every FlowFile going through the processor, equivalent to the \"basic\" usage in Apache NiFi.");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/standard-processors/processors/UpdateAttribute.h b/extensions/standard-processors/processors/UpdateAttribute.h
index 3e9c81e..1263167 100644
--- a/extensions/standard-processors/processors/UpdateAttribute.h
+++ b/extensions/standard-processors/processors/UpdateAttribute.h
@@ -28,7 +28,6 @@
 #include "core/Processor.h"
 #include "core/ProcessSession.h"
 #include "core/Core.h"
-#include "core/Resource.h"
 #include "core/logging/LoggerConfiguration.h"
 
 namespace org {
@@ -74,9 +73,6 @@ class UpdateAttribute : public core::Processor {
   std::vector<core::Property> attributes_;
 };
 
-REGISTER_RESOURCE(UpdateAttribute, "This processor updates the attributes of a FlowFile using properties that are added by the user. "
-  "This allows you to set default attribute changes that affect every FlowFile going through the processor, equivalent to the \"basic\" usage in Apache NiFi.");
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/standard-processors/tests/CMakeLists.txt b/extensions/standard-processors/tests/CMakeLists.txt
index 3dc530d..6ae3513 100644
--- a/extensions/standard-processors/tests/CMakeLists.txt
+++ b/extensions/standard-processors/tests/CMakeLists.txt
@@ -38,11 +38,11 @@ FOREACH(testfile ${PROCESSOR_UNIT_TESTS})
 	target_include_directories(${testfilename} BEFORE PRIVATE ./include)
     createTests("${testfilename}")
     target_link_libraries(${testfilename} ${CATCH_MAIN_LIB})
-	target_wholearchive_library(${testfilename} minifi-expression-language-extensions)
-	target_wholearchive_library(${testfilename} minifi-standard-processors)
-	target_wholearchive_library(${testfilename} minifi-civet-extensions)
+	target_link_libraries(${testfilename} minifi-expression-language-extensions)
+	target_link_libraries(${testfilename} minifi-standard-processors)
+	target_link_libraries(${testfilename} minifi-civet-extensions)
 	if (NOT DISABLE_ROCKSDB)
-		target_wholearchive_library(${testfilename} minifi-rocksdb-repos)
+		target_link_libraries(${testfilename} minifi-rocksdb-repos)
 	endif()
 	add_test(NAME "${testfilename}" COMMAND "${testfilename}" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
 
@@ -63,10 +63,10 @@ FOREACH(testfile ${PROCESSOR_INTEGRATION_TESTS})
 	target_include_directories(${testfilename} BEFORE PRIVATE ./include)
  	createTests("${testfilename}")
 	target_link_libraries(${testfilename})
-	target_wholearchive_library(${testfilename} minifi-standard-processors)
-	target_wholearchive_library(${testfilename} minifi-civet-extensions)
+	target_link_libraries(${testfilename} minifi-standard-processors)
+	target_link_libraries(${testfilename} minifi-civet-extensions)
 	if (NOT DISABLE_ROCKSDB)
-		target_wholearchive_library(${testfilename} minifi-rocksdb-repos)
+		target_link_libraries(${testfilename} minifi-rocksdb-repos)
 	endif()
 
 	MATH(EXPR INT_TEST_COUNT "${INT_TEST_COUNT}+1")
diff --git a/extensions/standard-processors/tests/integration/TLSClientSocketSupportedProtocolsTest.cpp b/extensions/standard-processors/tests/integration/TLSClientSocketSupportedProtocolsTest.cpp
index 1f600a1..efe7caa 100644
--- a/extensions/standard-processors/tests/integration/TLSClientSocketSupportedProtocolsTest.cpp
+++ b/extensions/standard-processors/tests/integration/TLSClientSocketSupportedProtocolsTest.cpp
@@ -28,6 +28,7 @@
 #include "io/tls/TLSSocket.h"
 
 #ifdef WIN32
+#pragma comment(lib, "Ws2_32.lib")
 using SocketDescriptor = SOCKET;
 #else
 using SocketDescriptor = int;
diff --git a/extensions/standard-processors/tests/integration/TLSServerSocketSupportedProtocolsTest.cpp b/extensions/standard-processors/tests/integration/TLSServerSocketSupportedProtocolsTest.cpp
index d892cda..3651aa8 100644
--- a/extensions/standard-processors/tests/integration/TLSServerSocketSupportedProtocolsTest.cpp
+++ b/extensions/standard-processors/tests/integration/TLSServerSocketSupportedProtocolsTest.cpp
@@ -32,6 +32,7 @@
 #ifdef WIN32
 #include <ws2tcpip.h>
 #include <winsock2.h>
+#pragma comment(lib, "Ws2_32.lib")
 #endif
 #include "properties/Configure.h"
 #include "io/tls/TLSSocket.h"
diff --git a/extensions/standard-processors/tests/unit/ClassLoaderTests.cpp b/extensions/standard-processors/tests/unit/ClassLoaderTests.cpp
index 37f1145..dde0d3e 100644
--- a/extensions/standard-processors/tests/unit/ClassLoaderTests.cpp
+++ b/extensions/standard-processors/tests/unit/ClassLoaderTests.cpp
@@ -16,10 +16,7 @@
  * limitations under the License.
  */
 #include "TestBase.h"
-#include "io/ClientSocket.h"
-#include "core/Processor.h"
 #include "core/ClassLoader.h"
-#include "core/yaml/YamlConfiguration.h"
 
 TEST_CASE("TestLoader", "[TestLoader]") {
   TestController controller;
diff --git a/extensions/standard-processors/tests/unit/ManifestTests.cpp b/extensions/standard-processors/tests/unit/ManifestTests.cpp
index 5d381a6..efe4b24 100644
--- a/extensions/standard-processors/tests/unit/ManifestTests.cpp
+++ b/extensions/standard-processors/tests/unit/ManifestTests.cpp
@@ -31,7 +31,7 @@
 #include "TailFile.h"
 
 TEST_CASE("Test Required", "[required]") {
-  minifi::state::response::ComponentManifest manifest("minifi-system");
+  minifi::state::response::ComponentManifest manifest("minifi-standard-processors");
   auto serialized = manifest.serialize();
   REQUIRE(serialized.size() > 0);
   const auto &resp = serialized[0];
diff --git a/extensions/standard-processors/tests/unit/ProcessorTests.cpp b/extensions/standard-processors/tests/unit/ProcessorTests.cpp
index 960655b..30b0344 100644
--- a/extensions/standard-processors/tests/unit/ProcessorTests.cpp
+++ b/extensions/standard-processors/tests/unit/ProcessorTests.cpp
@@ -15,6 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define EXTENSION_LIST "*minifi-*,!*http-curl*,!*coap*"
+
 #include <cstdio>
 #include <utility>
 #include <memory>
@@ -40,9 +42,11 @@
 #include "core/ProcessSession.h"
 #include "core/ProcessorNode.h"
 #include "core/reporting/SiteToSiteProvenanceReportingTask.h"
+#include "core/Resource.h"
 #include "utils/gsl.h"
 #include "utils/PropertyErrors.h"
 #include "utils/IntegrationTestUtils.h"
+#include "Utils.h"
 
 TEST_CASE("Test Creation of GetFile", "[getfileCreate]") {
   TestController testController;
diff --git a/extensions/systemd/CMakeLists.txt b/extensions/systemd/CMakeLists.txt
index f8cb6bc..1cb668b 100644
--- a/extensions/systemd/CMakeLists.txt
+++ b/extensions/systemd/CMakeLists.txt
@@ -19,8 +19,7 @@
 
 include(${CMAKE_SOURCE_DIR}/extensions/ExtensionHeader.txt)
 
-add_library(minifi-systemd STATIC ConsumeJournald.cpp WorkerThread.cpp libwrapper/LibWrapper.cpp libwrapper/DlopenWrapper.cpp)
-set_property(TARGET minifi-systemd PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-systemd SHARED ConsumeJournald.cpp WorkerThread.cpp libwrapper/LibWrapper.cpp libwrapper/DlopenWrapper.cpp)
 
 target_link_libraries(minifi-systemd ${LIBMINIFI} Threads::Threads date::date)
 
diff --git a/extensions/systemd/ConsumeJournald.cpp b/extensions/systemd/ConsumeJournald.cpp
index 162ec51..a0aeb24 100644
--- a/extensions/systemd/ConsumeJournald.cpp
+++ b/extensions/systemd/ConsumeJournald.cpp
@@ -24,6 +24,7 @@
 #include "spdlog/spdlog.h"  // TODO(szaszm): make fmt directly available
 #include "utils/GeneralUtils.h"
 #include "utils/OptionalUtils.h"
+#include "core/Resource.h"
 
 namespace org { namespace apache { namespace nifi { namespace minifi { namespace extensions { namespace systemd {
 
@@ -265,6 +266,9 @@ std::string ConsumeJournald::getCursor() const {
   return std::string{cursor.get()};
 }
 
+REGISTER_RESOURCE(ConsumeJournald, "Consume systemd-journald journal messages. Creates one flow file per message."
+    "Fields are mapped to attributes. Realtime timestamp is mapped to the 'timestamp' attribute.");
+
 }  // namespace systemd
 }  // namespace extensions
 }  // namespace minifi
diff --git a/extensions/systemd/ConsumeJournald.h b/extensions/systemd/ConsumeJournald.h
index e3468bb..25f86c9 100644
--- a/extensions/systemd/ConsumeJournald.h
+++ b/extensions/systemd/ConsumeJournald.h
@@ -31,7 +31,6 @@
 
 #include "core/CoreComponentState.h"
 #include "core/Processor.h"
-#include "core/Resource.h"
 #include "core/logging/Logger.h"
 #include "libwrapper/LibWrapper.h"
 #include "utils/Deleters.h"
@@ -103,9 +102,6 @@ class ConsumeJournald final : public core::Processor {
   std::string timestamp_format_ = "%x %X %Z";
 };
 
-REGISTER_RESOURCE(ConsumeJournald, "Consume systemd-journald journal messages. Creates one flow file per message."
-    "Fields are mapped to attributes. Realtime timestamp is mapped to the 'timestamp' attribute.");
-
 }  // namespace systemd
 }  // namespace extensions
 }  // namespace minifi
diff --git a/extensions/systemd/tests/CMakeLists.txt b/extensions/systemd/tests/CMakeLists.txt
index 5525afa..5ccc870 100644
--- a/extensions/systemd/tests/CMakeLists.txt
+++ b/extensions/systemd/tests/CMakeLists.txt
@@ -23,8 +23,8 @@ function(add_systemd_test testfile)
     target_include_directories(${TEST_TARGET} PRIVATE BEFORE "${CMAKE_SOURCE_DIR}/extensions/systemd/")
     target_include_directories(${TEST_TARGET} PRIVATE BEFORE "${CMAKE_SOURCE_DIR}/extensions/standard-processors")
     target_include_directories(${TEST_TARGET} PRIVATE BEFORE "${CMAKE_SOURCE_DIR}/libminifi/test")
-    target_wholearchive_library(${TEST_TARGET} minifi-systemd)
-    target_wholearchive_library(${TEST_TARGET} minifi-standard-processors)
+    target_link_libraries(${TEST_TARGET} minifi-systemd)
+    target_link_libraries(${TEST_TARGET} minifi-standard-processors)
     createTests("${TEST_TARGET}")
     add_test(NAME ${TEST_TARGET} COMMAND "${TEST_TARGET}" WORKING_DIRECTORY "${TEST_DIR}")
     target_link_libraries(${TEST_TARGET} ${CATCH_MAIN_LIB})
diff --git a/extensions/tensorflow/CMakeLists.txt b/extensions/tensorflow/CMakeLists.txt
index b6f74c2..76b8934 100644
--- a/extensions/tensorflow/CMakeLists.txt
+++ b/extensions/tensorflow/CMakeLists.txt
@@ -28,8 +28,7 @@ message("-- Found TensorFlow: ${TENSORFLOW_INCLUDE_DIRS}")
 
 file(GLOB SOURCES  "*.cpp")
 
-add_library(minifi-tensorflow-extensions STATIC ${SOURCES})
-set_property(TARGET minifi-tensorflow-extensions PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-tensorflow-extensions SHARED ${SOURCES})
 
 target_include_directories(minifi-tensorflow-extensions SYSTEM PRIVATE ${TENSORFLOW_INCLUDE_DIRS})
 target_link_libraries(minifi-tensorflow-extensions ${LIBMINIFI} Threads::Threads)
diff --git a/extensions/tensorflow/TFApplyGraph.cpp b/extensions/tensorflow/TFApplyGraph.cpp
index b14c2e3..ad30f75 100644
--- a/extensions/tensorflow/TFApplyGraph.cpp
+++ b/extensions/tensorflow/TFApplyGraph.cpp
@@ -227,6 +227,10 @@ int64_t TFApplyGraph::TensorWriteCallback::process(const std::shared_ptr<io::Bas
   return num_wrote;
 }
 
+REGISTER_RESOURCE(TFApplyGraph, "Applies a TensorFlow graph to the tensor protobuf supplied as input. The tensor is fed into the node specified by the Input Node property. "
+    "The output FlowFile is a tensor protobuf extracted from the node specified by the Output Node property. TensorFlow graphs are read dynamically by feeding a graph "
+    "protobuf to the processor with the tf.type property set to graph."); // NOLINT
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/tensorflow/TFApplyGraph.h b/extensions/tensorflow/TFApplyGraph.h
index e00d528..352c59a 100644
--- a/extensions/tensorflow/TFApplyGraph.h
+++ b/extensions/tensorflow/TFApplyGraph.h
@@ -104,10 +104,6 @@ class TFApplyGraph : public core::Processor {
   moodycamel::ConcurrentQueue<std::shared_ptr<TFContext>> tf_context_q_;
 };
 
-REGISTER_RESOURCE(TFApplyGraph, "Applies a TensorFlow graph to the tensor protobuf supplied as input. The tensor is fed into the node specified by the Input Node property. "
-    "The output FlowFile is a tensor protobuf extracted from the node specified by the Output Node property. TensorFlow graphs are read dynamically by feeding a graph "
-    "protobuf to the processor with the tf.type property set to graph."); // NOLINT
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/tensorflow/TFConvertImageToTensor.cpp b/extensions/tensorflow/TFConvertImageToTensor.cpp
index efa4716..c0fda3d 100644
--- a/extensions/tensorflow/TFConvertImageToTensor.cpp
+++ b/extensions/tensorflow/TFConvertImageToTensor.cpp
@@ -344,6 +344,8 @@ int64_t TFConvertImageToTensor::TensorWriteCallback::process(const std::shared_p
   return num_wrote;
 }
 
+REGISTER_RESOURCE(TFConvertImageToTensor, "Converts the input image file into a tensor protobuf. The image will be resized to the given output tensor dimensions."); // NOLINT
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/tensorflow/TFConvertImageToTensor.h b/extensions/tensorflow/TFConvertImageToTensor.h
index 93c5b38..f2b4999 100644
--- a/extensions/tensorflow/TFConvertImageToTensor.h
+++ b/extensions/tensorflow/TFConvertImageToTensor.h
@@ -107,8 +107,6 @@ class TFConvertImageToTensor : public core::Processor {
   moodycamel::ConcurrentQueue<std::shared_ptr<TFContext>> tf_context_q_;
 };
 
-REGISTER_RESOURCE(TFConvertImageToTensor, "Converts the input image file into a tensor protobuf. The image will be resized to the given output tensor dimensions."); // NOLINT
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/tensorflow/TFExtractTopLabels.cpp b/extensions/tensorflow/TFExtractTopLabels.cpp
index cfdaa9d..e8e0281 100644
--- a/extensions/tensorflow/TFExtractTopLabels.cpp
+++ b/extensions/tensorflow/TFExtractTopLabels.cpp
@@ -166,6 +166,8 @@ int64_t TFExtractTopLabels::TensorReadCallback::process(const std::shared_ptr<io
   return gsl::narrow<int64_t>(num_read);
 }
 
+REGISTER_RESOURCE(TFExtractTopLabels, "Extracts the top 5 labels for categorical inference models"); // NOLINT
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/tensorflow/TFExtractTopLabels.h b/extensions/tensorflow/TFExtractTopLabels.h
index 03ca8ca..255c635 100644
--- a/extensions/tensorflow/TFExtractTopLabels.h
+++ b/extensions/tensorflow/TFExtractTopLabels.h
@@ -81,8 +81,6 @@ class TFExtractTopLabels : public core::Processor {
   std::mutex labels_mtx_;
 };
 
-REGISTER_RESOURCE(TFExtractTopLabels, "Extracts the top 5 labels for categorical inference models"); // NOLINT
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/usb-camera/CMakeLists.txt b/extensions/usb-camera/CMakeLists.txt
index 87e8c02..1b466a7 100644
--- a/extensions/usb-camera/CMakeLists.txt
+++ b/extensions/usb-camera/CMakeLists.txt
@@ -49,8 +49,7 @@ endif()
 
 file(GLOB SOURCES  "*.cpp")
 
-add_library(minifi-usb-camera-extensions STATIC ${SOURCES})
-set_property(TARGET minifi-usb-camera-extensions PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-usb-camera-extensions SHARED ${SOURCES})
 
 target_link_libraries(minifi-usb-camera-extensions ${LIBMINIFI} Threads::Threads)
 target_link_libraries(minifi-usb-camera-extensions libuvc PNG::PNG)
diff --git a/extensions/usb-camera/GetUSBCamera.cpp b/extensions/usb-camera/GetUSBCamera.cpp
index 4d6d021..fcfd699 100644
--- a/extensions/usb-camera/GetUSBCamera.cpp
+++ b/extensions/usb-camera/GetUSBCamera.cpp
@@ -28,6 +28,7 @@
 #include <algorithm>
 
 #include "utils/gsl.h"
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -477,6 +478,8 @@ int64_t GetUSBCamera::RawWriteCallback::process(const std::shared_ptr<io::BaseSt
   return io::isError(write_ret) ? -1 : gsl::narrow<int64_t>(write_ret);
 }
 
+REGISTER_RESOURCE(GetUSBCamera, "Gets images from USB Video Class (UVC)-compatible devices. Outputs one flow file per frame at the rate specified by the FPS property in the format specified by the Format property.");  // NOLINT line length
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/usb-camera/GetUSBCamera.h b/extensions/usb-camera/GetUSBCamera.h
index f5053a1..2f133b6 100644
--- a/extensions/usb-camera/GetUSBCamera.h
+++ b/extensions/usb-camera/GetUSBCamera.h
@@ -31,7 +31,6 @@
 #include "core/ProcessSession.h"
 #include "core/Core.h"
 #include "core/logging/LoggerConfiguration.h"
-#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -138,8 +137,6 @@ class GetUSBCamera : public core::Processor {
   void cleanupUvc();
 };
 
-REGISTER_RESOURCE(GetUSBCamera, "Gets images from USB Video Class (UVC)-compatible devices. Outputs one flow file per frame at the rate specified by the FPS property in the format specified by the Format property.");  // NOLINT line length
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/windows-event-log/CMakeLists.txt b/extensions/windows-event-log/CMakeLists.txt
index 7aaf512..ec0791d 100644
--- a/extensions/windows-event-log/CMakeLists.txt
+++ b/extensions/windows-event-log/CMakeLists.txt
@@ -21,8 +21,7 @@ include(${CMAKE_SOURCE_DIR}/extensions/ExtensionHeader.txt)
 
 file(GLOB SOURCES  "*.cpp" "wel/*.cpp")
 
-add_library(minifi-wel STATIC ${SOURCES})
-set_property(TARGET minifi-wel PROPERTY POSITION_INDEPENDENT_CODE ON)
+add_library(minifi-wel SHARED ${SOURCES})
 
 target_link_libraries(minifi-wel ${LIBMINIFI} Threads::Threads)
 target_link_libraries(minifi-wel PUGI::libpugixml ZLIB::ZLIB Wevtapi.lib)
diff --git a/extensions/windows-event-log/CollectorInitiatedSubscription.cpp b/extensions/windows-event-log/CollectorInitiatedSubscription.cpp
index 4c74552..415df05 100644
--- a/extensions/windows-event-log/CollectorInitiatedSubscription.cpp
+++ b/extensions/windows-event-log/CollectorInitiatedSubscription.cpp
@@ -32,6 +32,7 @@
 #include "io/BufferStream.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 
 #include "utils/gsl.h"
 
@@ -702,6 +703,8 @@ void CollectorInitiatedSubscription::logWindowsError(int line, const std::string
   LocalFree(lpMsg);
 }
 
+REGISTER_RESOURCE(CollectorInitiatedSubscription, "Windows Event Log Subscribe Callback to receive FlowFiles from Events on Windows.");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/windows-event-log/CollectorInitiatedSubscription.h b/extensions/windows-event-log/CollectorInitiatedSubscription.h
index e9b6671..50a2d17 100644
--- a/extensions/windows-event-log/CollectorInitiatedSubscription.h
+++ b/extensions/windows-event-log/CollectorInitiatedSubscription.h
@@ -107,8 +107,6 @@ class CollectorInitiatedSubscription : public core::Processor {
   SupportedProperty<uint64_t> inactiveDurationToReconnect_;
 };
 
-REGISTER_RESOURCE(CollectorInitiatedSubscription, "Windows Event Log Subscribe Callback to receive FlowFiles from Events on Windows.");
-
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/windows-event-log/ConsumeWindowsEventLog.cpp b/extensions/windows-event-log/ConsumeWindowsEventLog.cpp
index 04a90a0..b152a9d 100644
--- a/extensions/windows-event-log/ConsumeWindowsEventLog.cpp
+++ b/extensions/windows-event-log/ConsumeWindowsEventLog.cpp
@@ -41,6 +41,7 @@
 #include "io/BufferStream.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
+#include "core/Resource.h"
 #include "Bookmark.h"
 #include "utils/Deleters.h"
 
@@ -762,6 +763,8 @@ void ConsumeWindowsEventLog::LogWindowsError(std::string error) const {
   LocalFree(lpMsg);
 }
 
+REGISTER_RESOURCE(ConsumeWindowsEventLog, "Windows Event Log Subscribe Callback to receive FlowFiles from Events on Windows.");
+
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/windows-event-log/ConsumeWindowsEventLog.h b/extensions/windows-event-log/ConsumeWindowsEventLog.h
index e40a8f4..0283176 100644
--- a/extensions/windows-event-log/ConsumeWindowsEventLog.h
+++ b/extensions/windows-event-log/ConsumeWindowsEventLog.h
@@ -42,6 +42,7 @@
 #include "FlowFileRecord.h"
 #include "concurrentqueue.h"
 #include "pugixml.hpp"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -71,27 +72,27 @@ class ConsumeWindowsEventLog : public core::Processor {
   virtual ~ConsumeWindowsEventLog();
 
   //! Processor Name
-  static const std::string ProcessorName;
+  EXTENSIONAPI static const std::string ProcessorName;
 
   //! Supported Properties
-  static core::Property Channel;
-  static core::Property Query;
-  static core::Property RenderFormatXML;
-  static core::Property MaxBufferSize;
-  static core::Property InactiveDurationToReconnect;
-  static core::Property IdentifierMatcher;
-  static core::Property IdentifierFunction;
-  static core::Property ResolveAsAttributes;
-  static core::Property EventHeaderDelimiter;
-  static core::Property EventHeader;
-  static core::Property OutputFormat;
-  static core::Property JSONFormat;
-  static core::Property BatchCommitSize;
-  static core::Property BookmarkRootDirectory;
-  static core::Property ProcessOldEvents;
+  EXTENSIONAPI static core::Property Channel;
+  EXTENSIONAPI static core::Property Query;
+  EXTENSIONAPI static core::Property RenderFormatXML;
+  EXTENSIONAPI static core::Property MaxBufferSize;
+  EXTENSIONAPI static core::Property InactiveDurationToReconnect;
+  EXTENSIONAPI static core::Property IdentifierMatcher;
+  EXTENSIONAPI static core::Property IdentifierFunction;
+  EXTENSIONAPI static core::Property ResolveAsAttributes;
+  EXTENSIONAPI static core::Property EventHeaderDelimiter;
+  EXTENSIONAPI static core::Property EventHeader;
+  EXTENSIONAPI static core::Property OutputFormat;
+  EXTENSIONAPI static core::Property JSONFormat;
+  EXTENSIONAPI static core::Property BatchCommitSize;
+  EXTENSIONAPI static core::Property BookmarkRootDirectory;
+  EXTENSIONAPI static core::Property ProcessOldEvents;
 
   //! Supported Relationships
-  static core::Relationship Success;
+  EXTENSIONAPI static core::Relationship Success;
 
  public:
   /**
@@ -182,8 +183,6 @@ class ConsumeWindowsEventLog : public core::Processor {
   std::string timezone_offset_;  // Represented as UTC offset in (+|-)HH:MM format, like +02:00
 };
 
-REGISTER_RESOURCE(ConsumeWindowsEventLog, "Windows Event Log Subscribe Callback to receive FlowFiles from Events on Windows.");
-
 }  // namespace processors
 }  // namespace minifi
 }  // namespace nifi
diff --git a/extensions/windows-event-log/TailEventLog.cpp b/extensions/windows-event-log/TailEventLog.cpp
index db93cba..d6e76c7 100644
--- a/extensions/windows-event-log/TailEventLog.cpp
+++ b/extensions/windows-event-log/TailEventLog.cpp
@@ -29,7 +29,7 @@
 #include "io/BufferStream.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
-
+#include "core/Resource.h"
 
 namespace org {
 namespace apache {
@@ -125,6 +125,9 @@ void TailEventLog::onTrigger(const std::shared_ptr<core::ProcessContext> &contex
     context->yield();
   }
 }
+
+REGISTER_RESOURCE(TailEventLog, "Windows event log reader that functions as a stateful tail of the provided windows event log name");
+
 } /* namespace processors */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/extensions/windows-event-log/TailEventLog.h b/extensions/windows-event-log/TailEventLog.h
index 5d8dfa5..9b8b548 100644
--- a/extensions/windows-event-log/TailEventLog.h
+++ b/extensions/windows-event-log/TailEventLog.h
@@ -137,7 +137,6 @@ class TailEventLog : public core::Processor {
   // Logger
   std::shared_ptr<logging::Logger> logger_;
 };
-REGISTER_RESOURCE(TailEventLog, "Windows event log reader that functions as a stateful tail of the provided windows event log name");
 
 } /* namespace processors */
 } /* namespace minifi */
diff --git a/extensions/windows-event-log/tests/CMakeLists.txt b/extensions/windows-event-log/tests/CMakeLists.txt
index 1f8c9f3..3f72012 100644
--- a/extensions/windows-event-log/tests/CMakeLists.txt
+++ b/extensions/windows-event-log/tests/CMakeLists.txt
@@ -35,9 +35,9 @@ FOREACH(testfile ${WEL_INTEGRATION_TESTS})
 	target_include_directories(${testfilename} BEFORE PRIVATE "${CMAKE_SOURCE_DIR}/libminifi/test/")
 	target_include_directories(${testfilename} BEFORE PRIVATE "${CMAKE_SOURCE_DIR}/libminifi/include/")
 	createTests("${testfilename}")
-	target_wholearchive_library(${testfilename} minifi-wel)
-	target_wholearchive_library(${testfilename} minifi-standard-processors)
-	target_link_libraries (${testfilename} minifi ${CATCH_MAIN_LIB})
+	target_link_libraries(${testfilename} minifi-wel)
+	target_link_libraries(${testfilename} minifi-standard-processors)
+	target_link_libraries (${testfilename} ${LIBMINIFI} ${CATCH_MAIN_LIB})
 
 	MATH(EXPR WEL_TEST_COUNT "${WEL_TEST_COUNT}+1")
 	add_test(NAME "${testfilename}" COMMAND "${testfilename}" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/libminifi/CMakeLists.txt b/libminifi/CMakeLists.txt
index 5432a8e..9466e97 100644
--- a/libminifi/CMakeLists.txt
+++ b/libminifi/CMakeLists.txt
@@ -57,7 +57,7 @@ if (NOT OPENSSL_OFF)
 	set(TLS_SOURCES "src/utils/tls/*.cpp" "src/io/tls/*.cpp")
 endif()
 
-file(GLOB SOURCES "src/properties/*.cpp" "src/utils/file/*.cpp" "src/sitetosite/*.cpp"  "src/core/logging/*.cpp" "src/core/logging/internal/*.cpp"  "src/core/state/*.cpp" "src/core/state/nodes/*.cpp" "src/c2/protocols/*.cpp" "src/c2/triggers/*.cpp" "src/c2/*.cpp" "src/io/*.cpp" ${SOCKET_SOURCES} ${TLS_SOURCES} "src/core/controller/*.cpp" "src/controllers/*.cpp" "src/controllers/keyvalue/*.cpp" "src/core/*.cpp"  "src/core/repository/*.cpp" "src/core/yaml/*.cpp" "src/core/reporting/*.cpp"  [...]
+file(GLOB SOURCES "src/agent/agent_docs.cpp" "src/properties/*.cpp" "src/utils/file/*.cpp" "src/sitetosite/*.cpp"  "src/core/logging/*.cpp" "src/core/logging/internal/*.cpp" "src/core/state/*.cpp" "src/core/state/nodes/*.cpp" "src/c2/protocols/*.cpp" "src/c2/triggers/*.cpp" "src/c2/*.cpp" "src/io/*.cpp" ${SOCKET_SOURCES} ${TLS_SOURCES} "src/core/controller/*.cpp" "src/controllers/*.cpp" "src/controllers/keyvalue/*.cpp" "src/core/*.cpp"  "src/core/repository/*.cpp" "src/core/yaml/*.cpp" " [...]
 # manually add this as it might not yet be present when this executes
 list(APPEND SOURCES "src/agent/agent_version.cpp")
 
@@ -75,10 +75,17 @@ endif()
 file(GLOB PROCESSOR_SOURCES  "src/processors/*.cpp" )
 
 
-add_library(core-minifi STATIC ${SOURCES})
+add_library(core-minifi SHARED ${SOURCES})
+target_compile_definitions(core-minifi PRIVATE "LIBMINIFI=1")
 if(WIN32)
-        add_dependencies(core-minifi message-strings)
-        target_include_directories(core-minifi PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/include")
+	set_target_properties(core-minifi PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
+	add_dependencies(core-minifi message-strings)
+	target_include_directories(core-minifi PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/include")
+	set_target_properties(core-minifi PROPERTIES
+			RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
+			ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
+else()
+	set_target_properties(core-minifi PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
 endif()
 
 if(NOT EXCLUDE_BOOST)
@@ -98,27 +105,16 @@ endif()
 if (NOT OPENSSL_OFF)
 	list(APPEND LIBMINIFI_LIBRARIES OpenSSL::Crypto OpenSSL::SSL)
 endif()
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9)
+	list(APPEND LIBMINIFI_LIBRARIES stdc++fs)
+endif()
 target_link_libraries(core-minifi ${CMAKE_DL_LIBS} ${LIBMINIFI_LIBRARIES})
 
+SET (LIBMINIFI core-minifi PARENT_SCOPE)
 
-add_library(minifi STATIC ${PROCESSOR_SOURCES})
-target_link_libraries(minifi core-minifi)
 if (WIN32)
-	set_target_properties(minifi PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
-	set_target_properties(minifi PROPERTIES LINK_FLAGS "${LINK_FLAGS} /WHOLEARCHIVE:core-minifi")
+	install(TARGETS core-minifi ARCHIVE DESTINATION bin COMPONENT bin)
+	install(TARGETS core-minifi RUNTIME DESTINATION bin COMPONENT bin)
+else()
+	install(TARGETS core-minifi LIBRARY DESTINATION bin COMPONENT bin)
 endif()
-
-
-SET (LIBMINIFI core-minifi PARENT_SCOPE)
-
-if (ENABLE_PYTHON AND NOT STATIC_BUILD)
-	add_library(core-minifi-shared SHARED ${SOURCES})
-	target_link_libraries(core-minifi-shared ${CMAKE_DL_LIBS} ${LIBMINIFI_LIBRARIES})
-
-	add_library(minifi-shared SHARED ${PROCESSOR_SOURCES})
-	target_link_libraries(minifi-shared core-minifi-shared)
-	if (WIN32)
-		set_target_properties(minifi-shared PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
-		set_target_properties(minifi-shared PROPERTIES LINK_FLAGS "${LINK_FLAGS} /WHOLEARCHIVE:core-minifi-shared")
-	endif()
-endif(ENABLE_PYTHON AND NOT STATIC_BUILD)
diff --git a/libminifi/include/FlowController.h b/libminifi/include/FlowController.h
index e764f82..50ae9e9 100644
--- a/libminifi/include/FlowController.h
+++ b/libminifi/include/FlowController.h
@@ -74,13 +74,11 @@ class FlowController : public core::controller::ForwardingControllerServiceProvi
   FlowController(std::shared_ptr<core::Repository> provenance_repo, std::shared_ptr<core::Repository> flow_file_repo,
                  std::shared_ptr<Configure> configure, std::unique_ptr<core::FlowConfiguration> flow_configuration,
                  std::shared_ptr<core::ContentRepository> content_repo, std::string name = DEFAULT_ROOT_GROUP_NAME,
-                 bool headless_mode = false, std::shared_ptr<utils::file::FileSystem> filesystem = std::make_shared<utils::file::FileSystem>());
+                 std::shared_ptr<utils::file::FileSystem> filesystem = std::make_shared<utils::file::FileSystem>());
 
   FlowController(std::shared_ptr<core::Repository> provenance_repo, std::shared_ptr<core::Repository> flow_file_repo,
                  std::shared_ptr<Configure> configure, std::unique_ptr<core::FlowConfiguration> flow_configuration,
-                 std::shared_ptr<core::ContentRepository> content_repo, std::shared_ptr<utils::file::FileSystem> filesystem)
-      : FlowController(std::move(provenance_repo), std::move(flow_file_repo), std::move(configure), std::move(flow_configuration),
-                       std::move(content_repo), DEFAULT_ROOT_GROUP_NAME, false, std::move(filesystem)) {}
+                 std::shared_ptr<core::ContentRepository> content_repo, std::shared_ptr<utils::file::FileSystem> filesystem);
 
   ~FlowController() override;
 
@@ -202,7 +200,6 @@ class FlowController : public core::controller::ForwardingControllerServiceProvi
  protected:
   // function to load the flow file repo.
   void loadFlowRepo();
-  void initializeExternalComponents();
 
   std::optional<std::chrono::milliseconds> loadShutdownTimeoutFromConfiguration();
 
diff --git a/libminifi/include/RemoteProcessorGroupPort.h b/libminifi/include/RemoteProcessorGroupPort.h
index be22fd0..f3bcc35 100644
--- a/libminifi/include/RemoteProcessorGroupPort.h
+++ b/libminifi/include/RemoteProcessorGroupPort.h
@@ -35,6 +35,7 @@
 #include "io/StreamFactory.h"
 #include "controllers/SSLContextService.h"
 #include "core/logging/LoggerConfiguration.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -103,15 +104,15 @@ class RemoteProcessorGroupPort : public core::Processor {
   virtual ~RemoteProcessorGroupPort() = default;
 
   // Processor Name
-  static const char *ProcessorName;
+  MINIFIAPI static const char *ProcessorName;
   // Supported Properties
-  static core::Property hostName;
-  static core::Property SSLContext;
-  static core::Property port;
-  static core::Property portUUID;
-  static core::Property idleTimeout;
+  MINIFIAPI static core::Property hostName;
+  MINIFIAPI static core::Property SSLContext;
+  MINIFIAPI static core::Property port;
+  MINIFIAPI static core::Property portUUID;
+  MINIFIAPI static core::Property idleTimeout;
   // Supported Relationships
-  static core::Relationship relation;
+  MINIFIAPI static core::Relationship relation;
 
  public:
   virtual void onSchedule(const std::shared_ptr<core::ProcessContext> &context, const std::shared_ptr<core::ProcessSessionFactory> &sessionFactory);
diff --git a/libminifi/include/agent/agent_docs.h b/libminifi/include/agent/agent_docs.h
index 8ce45ec..53afb58 100644
--- a/libminifi/include/agent/agent_docs.h
+++ b/libminifi/include/agent/agent_docs.h
@@ -29,10 +29,7 @@ namespace nifi {
 namespace minifi {
 class AgentDocs {
  private:
-  static std::map<std::string, std::string> &getDescriptions() {
-    static std::map<std::string, std::string> extensions;
-    return extensions;
-  }
+  static std::map<std::string, std::string> &getDescriptions();
 
  public:
   /**
diff --git a/libminifi/include/agent/agent_version.h b/libminifi/include/agent/agent_version.h
index d7a70a1..ac38cf2 100644
--- a/libminifi/include/agent/agent_version.h
+++ b/libminifi/include/agent/agent_version.h
@@ -20,6 +20,7 @@
 
 #include <string>
 #include <vector>
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -28,13 +29,13 @@ namespace minifi {
 
 class AgentBuild {
  public:
-  static const char* const VERSION;
-  static const char* const BUILD_IDENTIFIER;
-  static const char* const BUILD_REV;
-  static const char* const BUILD_DATE;
-  static const char* const COMPILER;
-  static const char* const COMPILER_VERSION;
-  static const char* const COMPILER_FLAGS;
+  MINIFIAPI static const char* const VERSION;
+  MINIFIAPI static const char* const BUILD_IDENTIFIER;
+  MINIFIAPI static const char* const BUILD_REV;
+  MINIFIAPI static const char* const BUILD_DATE;
+  MINIFIAPI static const char* const COMPILER;
+  MINIFIAPI static const char* const COMPILER_VERSION;
+  MINIFIAPI static const char* const COMPILER_FLAGS;
   static std::vector<std::string> getExtensions();
 };
 
diff --git a/libminifi/include/c2/ControllerSocketProtocol.h b/libminifi/include/c2/ControllerSocketProtocol.h
index c5e9dce..7637ef6 100644
--- a/libminifi/include/c2/ControllerSocketProtocol.h
+++ b/libminifi/include/c2/ControllerSocketProtocol.h
@@ -23,7 +23,6 @@
 #include <string>
 #include <vector>
 
-#include "core/Resource.h"
 #include "HeartbeatReporter.h"
 #include "io/StreamFactory.h"
 #include "core/logging/LoggerConfiguration.h"
@@ -84,8 +83,6 @@ class ControllerSocketProtocol : public HeartbeatReporter {
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(ControllerSocketProtocol, "Creates a reporter that can handle basic c2 operations for a localized environment through a simple TCP socket.");
-
 }  // namespace c2
 }  // namespace minifi
 }  // namespace nifi
diff --git a/libminifi/include/c2/HeartbeatLogger.h b/libminifi/include/c2/HeartbeatLogger.h
index 17ef729..587d4a6 100644
--- a/libminifi/include/c2/HeartbeatLogger.h
+++ b/libminifi/include/c2/HeartbeatLogger.h
@@ -40,8 +40,6 @@ class HeartbeatLogger : public RESTProtocol, public HeartbeatReporter {
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(HeartbeatLogger, "Logs heartbeats at TRACE level.");
-
 }  // namespace c2
 }  // namespace minifi
 }  // namespace nifi
diff --git a/libminifi/include/c2/triggers/FileUpdateTrigger.h b/libminifi/include/c2/triggers/FileUpdateTrigger.h
index 7bd8635..0c4b338 100644
--- a/libminifi/include/c2/triggers/FileUpdateTrigger.h
+++ b/libminifi/include/c2/triggers/FileUpdateTrigger.h
@@ -24,7 +24,6 @@
 #include "c2/C2Trigger.h"
 #include "utils/StringUtils.h"
 #include "utils/file/FileUtils.h"
-#include "core/Resource.h"
 #include "c2/C2Payload.h"
 #include "properties/Configure.h"
 
@@ -115,8 +114,6 @@ class FileUpdateTrigger : public C2Trigger {
  private:
   std::shared_ptr<logging::Logger> logger_;
 };
-// add the trigger to the known resources.
-REGISTER_RESOURCE(FileUpdateTrigger, "Defines a file update trigger when the last write time of a file has been changed.");
 
 }  // namespace c2
 }  // namespace minifi
diff --git a/libminifi/include/controllers/LinuxPowerManagementService.h b/libminifi/include/controllers/LinuxPowerManagementService.h
index f3213d3..790f258 100644
--- a/libminifi/include/controllers/LinuxPowerManagementService.h
+++ b/libminifi/include/controllers/LinuxPowerManagementService.h
@@ -23,7 +23,6 @@
 #include <vector>
 #include <iostream>
 #include <memory>
-#include "core/Resource.h"
 #include "utils/StringUtils.h"
 #include "io/validation.h"
 #include "core/controller/ControllerService.h"
@@ -127,8 +126,6 @@ class LinuxPowerManagerService : public ThreadManagementService {
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(LinuxPowerManagerService, "Linux power management service that enables control of power usage in the agent through Linux power management information. Use name \"ThreadPoolManager\" to throttle battery consumption"); // NOLINT
-
 }  // namespace controllers
 }  // namespace minifi
 }  // namespace nifi
diff --git a/libminifi/include/controllers/NetworkPrioritizerService.h b/libminifi/include/controllers/NetworkPrioritizerService.h
index c014cbe..02faa55 100644
--- a/libminifi/include/controllers/NetworkPrioritizerService.h
+++ b/libminifi/include/controllers/NetworkPrioritizerService.h
@@ -25,7 +25,6 @@
 #include <utility>
 #include <vector>
 
-#include "core/Resource.h"
 #include "utils/StringUtils.h"
 #include "io/validation.h"
 #include "controllers/SSLContextService.h"
@@ -33,6 +32,7 @@
 #include "core/logging/LoggerConfiguration.h"
 #include "ThreadManagementService.h"
 #include "io/NetworkPrioritizer.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -67,11 +67,11 @@ class NetworkPrioritizerService : public core::controller::ControllerService, pu
     initialize();
   }
 
-  static core::Property NetworkControllers;
-  static core::Property MaxThroughput;
-  static core::Property MaxPayload;
-  static core::Property VerifyInterfaces;
-  static core::Property DefaultPrioritizer;
+  MINIFIAPI static core::Property NetworkControllers;
+  MINIFIAPI static core::Property MaxThroughput;
+  MINIFIAPI static core::Property MaxPayload;
+  MINIFIAPI static core::Property VerifyInterfaces;
+  MINIFIAPI static core::Property DefaultPrioritizer;
 
   void initialize();
 
@@ -130,8 +130,6 @@ class NetworkPrioritizerService : public core::controller::ControllerService, pu
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(NetworkPrioritizerService, "Enables selection of networking interfaces on defined parameters to include ouput and payload size");
-
 }  // namespace controllers
 }  // namespace minifi
 }  // namespace nifi
diff --git a/libminifi/include/controllers/SSLContextService.h b/libminifi/include/controllers/SSLContextService.h
index 8afbf0d..4162e31 100644
--- a/libminifi/include/controllers/SSLContextService.h
+++ b/libminifi/include/controllers/SSLContextService.h
@@ -36,12 +36,12 @@
 #include <iostream>
 #include <memory>
 #include <string>
-#include "core/Resource.h"
 #include "utils/StringUtils.h"
 #include "utils/tls/ExtendedKeyUsage.h"
 #include "io/validation.h"
 #include "../core/controller/ControllerService.h"
 #include "core/logging/LoggerConfiguration.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -172,17 +172,17 @@ class SSLContextService : public core::controller::ControllerService {
 
   virtual void onEnable();
 
-  static const core::Property ClientCertificate;
-  static const core::Property PrivateKey;
-  static const core::Property Passphrase;
-  static const core::Property CACertificate;
-  static const core::Property UseSystemCertStore;
+  MINIFIAPI static const core::Property ClientCertificate;
+  MINIFIAPI static const core::Property PrivateKey;
+  MINIFIAPI static const core::Property Passphrase;
+  MINIFIAPI static const core::Property CACertificate;
+  MINIFIAPI static const core::Property UseSystemCertStore;
 #ifdef WIN32
-  static const core::Property CertStoreLocation;
-  static const core::Property ServerCertStore;
-  static const core::Property ClientCertStore;
-  static const core::Property ClientCertCN;
-  static const core::Property ClientCertKeyUsage;
+  MINIFIAPI static const core::Property CertStoreLocation;
+  MINIFIAPI static const core::Property ServerCertStore;
+  MINIFIAPI static const core::Property ClientCertStore;
+  MINIFIAPI static const core::Property ClientCertCN;
+  MINIFIAPI static const core::Property ClientCertKeyUsage;
 #endif  // WIN32
 
  protected:
@@ -236,7 +236,6 @@ class SSLContextService : public core::controller::ControllerService {
   std::shared_ptr<logging::Logger> logger_;
 };
 typedef int (SSLContextService::*ptr)(char *, int, int, void *);
-REGISTER_RESOURCE(SSLContextService, "Controller service that provides SSL/TLS capabilities to consuming interfaces");
 
 }  // namespace controllers
 }  // namespace minifi
diff --git a/libminifi/include/controllers/ThreadManagementService.h b/libminifi/include/controllers/ThreadManagementService.h
index 904e56c..839941c 100644
--- a/libminifi/include/controllers/ThreadManagementService.h
+++ b/libminifi/include/controllers/ThreadManagementService.h
@@ -21,7 +21,6 @@
 #include <string>
 #include <iostream>
 #include <memory>
-#include "core/Resource.h"
 #include "utils/StringUtils.h"
 #include "io/validation.h"
 #include "core/controller/ControllerService.h"
diff --git a/libminifi/include/controllers/UpdatePolicyControllerService.h b/libminifi/include/controllers/UpdatePolicyControllerService.h
index 9dbf224..bc6ded9 100644
--- a/libminifi/include/controllers/UpdatePolicyControllerService.h
+++ b/libminifi/include/controllers/UpdatePolicyControllerService.h
@@ -22,12 +22,12 @@
 #include <iostream>
 #include <memory>
 #include <limits>
-#include "core/Resource.h"
 #include "utils/StringUtils.h"
 #include "io/validation.h"
 #include "core/controller/ControllerService.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "core/state/UpdatePolicy.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -54,10 +54,10 @@ class UpdatePolicyControllerService : public core::controller::ControllerService
     initialize();
   }
 
-  static core::Property AllowAllProperties;
-  static core::Property PersistUpdates;
-  static core::Property AllowedProperties;
-  static core::Property DisallowedProperties;
+  MINIFIAPI static core::Property AllowAllProperties;
+  MINIFIAPI static core::Property PersistUpdates;
+  MINIFIAPI static core::Property AllowedProperties;
+  MINIFIAPI static core::Property DisallowedProperties;
 
   void initialize();
 
@@ -83,9 +83,6 @@ class UpdatePolicyControllerService : public core::controller::ControllerService
   std::shared_ptr<logging::Logger> logger_;
 };
 
-REGISTER_RESOURCE(UpdatePolicyControllerService, "UpdatePolicyControllerService allows a flow specific policy on allowing or disallowing updates. "
-    "Since the flow dictates the purpose of a device it will also be used to dictate updates to specific components.");
-
 }  // namespace controllers
 }  // namespace minifi
 }  // namespace nifi
diff --git a/libminifi/include/controllers/keyvalue/AbstractAutoPersistingKeyValueStoreService.h b/libminifi/include/controllers/keyvalue/AbstractAutoPersistingKeyValueStoreService.h
index e347a70..89ee0c6 100644
--- a/libminifi/include/controllers/keyvalue/AbstractAutoPersistingKeyValueStoreService.h
+++ b/libminifi/include/controllers/keyvalue/AbstractAutoPersistingKeyValueStoreService.h
@@ -28,7 +28,7 @@
 #include "properties/Configure.h"
 #include "core/logging/Logger.h"
 #include "core/logging/LoggerConfiguration.h"
-#include "core/Resource.h"
+#include "utils/Export.h"
 
 
 namespace org {
@@ -43,8 +43,8 @@ class AbstractAutoPersistingKeyValueStoreService : virtual public PersistableKey
 
   ~AbstractAutoPersistingKeyValueStoreService() override;
 
-  static core::Property AlwaysPersist;
-  static core::Property AutoPersistenceInterval;
+  MINIFIAPI static core::Property AlwaysPersist;
+  MINIFIAPI static core::Property AutoPersistenceInterval;
 
   void initialize() override;
   void onEnable() override;
diff --git a/libminifi/include/core/ClassLoader.h b/libminifi/include/core/ClassLoader.h
index 99d2061..170eb6b 100644
--- a/libminifi/include/core/ClassLoader.h
+++ b/libminifi/include/core/ClassLoader.h
@@ -25,18 +25,9 @@
 #include <map>
 #include <memory>
 #include "utils/StringUtils.h"
-#ifndef WIN32
-#include <dlfcn.h>
-#define DLL_EXPORT
-#else
-#define WIN32_LEAN_AND_MEAN 1
-#include <Windows.h>    // Windows specific libraries for collecting software metrics.
-#include <Psapi.h>
-#pragma comment(lib, "psapi.lib" )
-#define DLL_EXPORT __declspec(dllexport)
-#endif
 #include "core/Core.h"
 #include "io/BufferStream.h"
+#include "ObjectFactory.h"
 
 namespace org {
 namespace apache {
@@ -57,188 +48,6 @@ namespace core {
 #endif
 
 /**
- * Class used to provide a global initialization and deinitialization function for an ObjectFactory.
- * Calls to instances of all ObjectFactoryInitializers are done under a unique lock.
- */
-class ObjectFactoryInitializer {
- public:
-  virtual ~ObjectFactoryInitializer() = default;
-
-  /**
-   * This function is be called before the ObjectFactory is used.
-   * @return whether the initialization was successful. If false, deinitialize will NOT be called.
-   */
-  virtual bool initialize() = 0;
-
-  /**
-   * This function will be called after the ObjectFactory is not needed anymore.
-   */
-  virtual void deinitialize() = 0;
-};
-
-/**
- * Factory that is used as an interface for
- * creating processors from shared objects.
- */
-class ObjectFactory {
- public:
-  ObjectFactory(const std::string &group) // NOLINT
-      : group_(group) {
-  }
-
-  ObjectFactory() = default;
-
-  /**
-   * Virtual destructor.
-   */
-  virtual ~ObjectFactory() = default;
-
-  /**
-   * Create a shared pointer to a new processor.
-   */
-  virtual std::shared_ptr<CoreComponent> create(const std::string& /*name*/) {
-    return nullptr;
-  }
-
-  /**
-   * Create a shared pointer to a new processor.
-   */
-  virtual CoreComponent *createRaw(const std::string& /*name*/) {
-    return nullptr;
-  }
-
-  /**
-   * Create a shared pointer to a new processor.
-   */
-  virtual std::shared_ptr<CoreComponent> create(const std::string& /*name*/, const utils::Identifier& /*uuid*/) {
-    return nullptr;
-  }
-
-  /**
-   * Create a shared pointer to a new processor.
-   */
-  virtual CoreComponent* createRaw(const std::string& /*name*/, const utils::Identifier& /*uuid*/) {
-    return nullptr;
-  }
-
-  /**
-   * Returns an initializer for the factory.
-   */
-  virtual std::unique_ptr<ObjectFactoryInitializer> getInitializer() {
-    return nullptr;
-  }
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  virtual std::string getName() = 0;
-
-  virtual std::string getGroupName() const {
-    return group_;
-  }
-
-  virtual std::string getClassName() = 0;
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  virtual std::vector<std::string> getClassNames() = 0;
-
-  virtual std::unique_ptr<ObjectFactory> assign(const std::string &class_name) = 0;
-
- private:
-  std::string group_;
-};
-/**
- * Factory that is used as an interface for
- * creating processors from shared objects.
- */
-template<class T>
-class DefautObjectFactory : public ObjectFactory {
- public:
-  DefautObjectFactory() {
-    className = core::getClassName<T>();
-  }
-
-  DefautObjectFactory(const std::string &group_name) // NOLINT
-      : ObjectFactory(group_name) {
-    className = core::getClassName<T>();
-  }
-  /**
-   * Virtual destructor.
-   */
-  virtual ~DefautObjectFactory() = default;
-
-  /**
-   * Create a shared pointer to a new processor.
-   */
-  virtual std::shared_ptr<CoreComponent> create(const std::string &name) {
-    std::shared_ptr<T> ptr = std::make_shared<T>(name);
-    return std::static_pointer_cast<CoreComponent>(ptr);
-  }
-
-  /**
-   * Create a shared pointer to a new processor.
-   */
-  virtual std::shared_ptr<CoreComponent> create(const std::string &name, const utils::Identifier &uuid) {
-    std::shared_ptr<T> ptr = std::make_shared<T>(name, uuid);
-    return std::static_pointer_cast<CoreComponent>(ptr);
-  }
-
-  /**
-   * Create a shared pointer to a new processor.
-   */
-  virtual CoreComponent* createRaw(const std::string &name) {
-    T *ptr = new T(name);
-    return dynamic_cast<CoreComponent*>(ptr);
-  }
-
-  /**
-   * Create a shared pointer to a new processor.
-   */
-  virtual CoreComponent* createRaw(const std::string &name, const utils::Identifier &uuid) {
-    T *ptr = new T(name, uuid);
-    return dynamic_cast<CoreComponent*>(ptr);
-  }
-
-  /**
-   * Gets the name of the object.
-   * @return class name of processor
-   */
-  virtual std::string getName() {
-    return className;
-  }
-
-  /**
-   * Gets the class name for the object
-   * @return class name for the processor.
-   */
-  virtual std::string getClassName() {
-    return className;
-  }
-
-  virtual std::vector<std::string> getClassNames() {
-    std::vector<std::string> container;
-    container.push_back(className);
-    return container;
-  }
-
-  virtual std::unique_ptr<ObjectFactory> assign(const std::string& /*class_name*/) {
-    return nullptr;
-  }
-
- protected:
-  std::string className;
-};
-
-/**
- * Function that is used to create the
- * processor factory from the shared object.
- */
-typedef ObjectFactory* createFactory();
-
-/**
  * Processor class loader that accepts
  * a variety of mechanisms to load in shared
  * objects.
@@ -250,130 +59,72 @@ class ClassLoader {
   /**
    * Constructor.
    */
-  ClassLoader();
-
-  ~ClassLoader() {
-    for (auto& initializer : initializers_) {
-      initializer->deinitialize();
-    }
-    loaded_factories_.clear();
-    for (auto ptr : dl_handles_) {
-      dlclose(ptr);
-    }
-  }
-
-  /**
-   * Sets the class loader
-   * @param name name of class loader
-   * @param loader loader unique ptr
-   * @return result of insertion
-   */
-  bool setClassLoader(const std::string &name, std::unique_ptr<ClassLoader> loader) {
-    if (nullptr != getClassLoader(name)) {
-      throw std::runtime_error("Cannot have more than one classloader with the same name");
-    }
-    std::lock_guard<std::mutex> lock(internal_mutex_);
-    // return validation that we inserted the class loader
-    return class_loaders_.insert(std::make_pair(name, std::move(loader))).second;
-  }
+  explicit ClassLoader(const std::string& name = "/");
 
   /**
    * Retrieves a class loader
    * @param name name of class loader
-   * @return class loader ptr if it exists, nullptr if it does not
-   */
-  ClassLoader *getClassLoader(const std::string &name) {
-    std::lock_guard<std::mutex> lock(internal_mutex_);
-    auto cld = class_loaders_.find(name);
-    if (cld != class_loaders_.end()) {
-      cld->second.get();
-    }
-    return nullptr;
-  }
-
-  /**
-   * Register the file system resource.
-   * This will attempt to load objects within this resource.
-   * @return return code: RESOURCE_FAILURE or RESOURCE_SUCCESS
+   * @return class loader reference
    */
-  uint16_t registerResource(const std::string &resource, const std::string &resourceName);
+  ClassLoader& getClassLoader(const std::string& child_name);
 
   /**
    * Register a class with the give ProcessorFactory
    */
-  void registerClass(const std::string &name, std::unique_ptr<ObjectFactory> factory) {
+  void registerClass(const std::string &clazz, std::unique_ptr<ObjectFactory> factory) {
     std::lock_guard<std::mutex> lock(internal_mutex_);
-    if (loaded_factories_.find(name) != loaded_factories_.end()) {
+    if (loaded_factories_.find(clazz) != loaded_factories_.end()) {
+      logger_->log_error("Class '%s' is already registered at '%s'", clazz, name_);
       return;
     }
-
-    auto initializer = factory->getInitializer();
-    if (initializer != nullptr) {
-      initializer->initialize();
-      initializers_.emplace_back(std::move(initializer));
-    }
-
-    auto canonical_name = factory->getClassName();
-
-    auto group_name = factory->getGroupName();
-
-    module_mapping_[group_name].push_back(canonical_name);
-    if (canonical_name != name)
-      class_to_group_[canonical_name] = group_name;
-    class_to_group_[name] = group_name;
-
-    loaded_factories_.insert(std::make_pair(name, std::move(factory)));
+    logger_->log_trace("Registering class '%s' at '%s'", clazz, name_);
+    loaded_factories_.insert(std::make_pair(clazz, std::move(factory)));
   }
 
-  std::vector<std::string> getClasses(const std::string &group) {
+  void unregisterClass(const std::string& clazz) {
     std::lock_guard<std::mutex> lock(internal_mutex_);
-    return module_mapping_[group];
-  }
-
-  std::vector<std::string> getGroups() {
-    std::vector<std::string> groups;
-    std::lock_guard<std::mutex> lock(internal_mutex_);
-    for (auto & resource : loaded_factories_) {
-      groups.push_back(resource.first);
+    if (loaded_factories_.erase(clazz) == 0) {
+      logger_->log_error("Could not unregister non-registered class '%s' at '%s'", clazz, name_);
+      return;
+    } else {
+      logger_->log_trace("Unregistered class '%s' at '%s'", clazz, name_);
     }
-    return groups;
   }
 
-  std::vector<std::string> getClasses() {
-    std::vector<std::string> groups;
+  std::vector<std::string> getClasses(const std::string &group) const {
     std::lock_guard<std::mutex> lock(internal_mutex_);
-    for (auto & resource : loaded_factories_) {
-      if (nullptr != resource.second) {
-        auto classes = resource.second->getClassNames();
-        groups.insert(groups.end(), classes.begin(), classes.end());
-      } else {
+    std::vector<std::string> classes;
+    for (const auto& child_loader : class_loaders_) {
+      for (auto&& clazz : child_loader.second.getClasses(group)) {
+        classes.push_back(std::move(clazz));
       }
     }
-    return groups;
+    for (const auto& factory : loaded_factories_) {
+      if (factory.second->getGroupName() == group) {
+        classes.push_back(factory.second->getClassName());
+      }
+    }
+    return classes;
   }
 
-  std::string getGroupForClass(const std::string &class_name) {
+  std::optional<std::string> getGroupForClass(const std::string &class_name) const {
     std::lock_guard<std::mutex> lock(internal_mutex_);
-    auto factory_entry = class_to_group_.find(class_name);
-    if (factory_entry != class_to_group_.end()) {
-      return factory_entry->second;
-    } else {
-      return "";
+    for (const auto& child_loader : class_loaders_) {
+      std::optional<std::string> group = child_loader.second.getGroupForClass(class_name);
+      if (group) {
+        return group;
+      }
+    }
+    auto factory = loaded_factories_.find(class_name);
+    if (factory != loaded_factories_.end()) {
+      return factory->second->getGroupName();
     }
+    return {};
   }
 
   /**
    * Instantiate object based on class_name
    * @param class_name class to create
-   * @param make_shared_ptr creates a shared ptr of the given type name
-   * @return nullptr, object created from class_name definition, or make_shared of T
-   */
-  template<class T>
-  std::shared_ptr<T> instantiate(const std::string &class_name, bool make_shared_ptr = true);
-
-  /**
-   * Instantiate object based on class_name
-   * @param class_name class to create
    * @param uuid uuid of object
    * @return nullptr or object created from class_name definition.
    */
@@ -398,209 +149,67 @@ class ClassLoader {
   template<class T = CoreComponent>
   T *instantiateRaw(const std::string &class_name, const std::string &name);
 
-  /**
-   * Instantiate object based on class_name
-   * @param class_name class to create
-   * @param uuid uuid of object
-   * @return nullptr or object created from class_name definition.
-   */
-  template<class T = CoreComponent>
-  T *instantiateRaw(const std::string &class_name, const utils::Identifier &uuid);
-
  protected:
-#ifdef WIN32
-
-  // base_object doesn't have a handle
-  std::map< HMODULE, std::string > resource_mapping_;
-
-  std::string error_str_;
-  std::string current_error_;
-
-  void store_error() {
-    auto error = GetLastError();
-
-    if (error == 0) {
-      error_str_ = "";
-      return;
-    }
-
-    LPSTR messageBuffer = nullptr;
-    size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
-        NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
-
-    current_error_ = std::string(messageBuffer, size);
-
-    // Free the buffer.
-    LocalFree(messageBuffer);
-  }
-
-  void *dlsym(void *handle, const char *name) {
-    FARPROC symbol;
-
-    symbol = GetProcAddress((HMODULE)handle, name);
-
-    if (symbol == nullptr) {
-      store_error();
-
-      for (auto hndl : resource_mapping_) {
-        symbol = GetProcAddress((HMODULE)hndl.first, name);
-        if (symbol != nullptr) {
-          break;
-        }
-      }
-    }
-
-#ifdef _MSC_VER
-#pragma warning(suppress: 4054 )
-#endif
-    return reinterpret_cast<void*>(symbol);
-  }
-
-  const char *dlerror(void) {
-    std::lock_guard<std::mutex> lock(internal_mutex_);
-
-    error_str_ = current_error_;
-
-    current_error_ = "";
-
-    return error_str_.c_str();
-  }
-
-  void *dlopen(const char *file, int mode) {
-    std::lock_guard<std::mutex> lock(internal_mutex_);
-    HMODULE object;
-    uint32_t uMode = SetErrorMode(SEM_FAILCRITICALERRORS);
-    if (nullptr == file) {
-      HMODULE allModules[1024];
-      HANDLE current_process_id = GetCurrentProcess();
-      DWORD cbNeeded;
-      object = GetModuleHandle(NULL);
-
-      if (!object)
-      store_error();
-      if (EnumProcessModules(current_process_id, allModules,
-              sizeof(allModules), &cbNeeded) != 0) {
-        for (uint32_t i = 0; i < cbNeeded / sizeof(HMODULE); i++) {
-          // Get the full path to the module's file.
-          resource_mapping_.insert(std::make_pair(allModules[i], "minifi-system"));
-        }
-      }
-    } else {
-      char lpFileName[MAX_PATH];
-      int i;
-
-      for (i = 0; i < sizeof(lpFileName) - 1; i++) {
-        if (!file[i])
-        break;
-        else if (file[i] == '/')
-        lpFileName[i] = '\\';
-        else
-        lpFileName[i] = file[i];
-      }
-      lpFileName[i] = '\0';
-      object = LoadLibraryEx(lpFileName, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
-      if (!object)
-      store_error();
-      else if ((mode & RTLD_GLOBAL))
-      resource_mapping_.insert(std::make_pair(object, lpFileName));
-    }
-
-    /* Return to previous state of the error-mode bit flags. */
-    SetErrorMode(uMode);
-
-    return reinterpret_cast<void*>(object);
-  }
-
-  int dlclose(void *handle) {
-    std::lock_guard<std::mutex> lock(internal_mutex_);
-
-    HMODULE object = (HMODULE)handle;
-    BOOL ret;
-
-    current_error_ = "";
-    ret = FreeLibrary(object);
-
-    resource_mapping_.erase(object);
-
-    ret = !ret;
-
-    return static_cast<int>(ret);
-  }
-
-#endif
-
-  std::map<std::string, std::vector<std::string>> module_mapping_;
-
   std::map<std::string, std::unique_ptr<ObjectFactory>> loaded_factories_;
 
-  std::map<std::string, std::string> class_to_group_;
-
-  // other class loaders
+  std::map<std::string, ClassLoader> class_loaders_;
 
-  std::map<std::string, std::unique_ptr<ClassLoader>> class_loaders_;
+  mutable std::mutex internal_mutex_;
 
-  std::mutex internal_mutex_;
+  std::shared_ptr<logging::Logger> logger_;
 
-  std::vector<void *> dl_handles_;
-
-  std::vector<std::unique_ptr<ObjectFactoryInitializer>> initializers_;
+  std::string name_;
 };
 
 template<class T>
-std::shared_ptr<T> ClassLoader::instantiate(const std::string &class_name, bool make_shared_ptr) {
-  const auto ret = instantiate<T>(class_name, class_name);
-  if (nullptr == ret && make_shared_ptr) {
-    return std::make_shared<T>(class_name);
-  }
-  return ret;
-}
-
-template<class T>
 std::shared_ptr<T> ClassLoader::instantiate(const std::string &class_name, const std::string &name) {
   std::lock_guard<std::mutex> lock(internal_mutex_);
+  // allow subsequent classes to override functionality (like ProcessContextBuilder)
+  for (auto& child_loader : class_loaders_) {
+    if (auto result = child_loader.second.instantiate<T>(class_name, name)) {
+      return result;
+    }
+  }
   auto factory_entry = loaded_factories_.find(class_name);
   if (factory_entry != loaded_factories_.end()) {
     auto obj = factory_entry->second->create(name);
     return std::dynamic_pointer_cast<T>(obj);
-  } else {
-    return nullptr;
   }
+  return nullptr;
 }
 
 template<class T>
 std::shared_ptr<T> ClassLoader::instantiate(const std::string &class_name, const utils::Identifier &uuid) {
   std::lock_guard<std::mutex> lock(internal_mutex_);
+  // allow subsequent classes to override functionality (like ProcessContextBuilder)
+  for (auto& child_loader : class_loaders_) {
+    if (auto result = child_loader.second.instantiate<T>(class_name, uuid)) {
+      return result;
+    }
+  }
   auto factory_entry = loaded_factories_.find(class_name);
   if (factory_entry != loaded_factories_.end()) {
     auto obj = factory_entry->second->create(class_name, uuid);
     return std::dynamic_pointer_cast<T>(obj);
-  } else {
-    return nullptr;
   }
+  return nullptr;
 }
 
 template<class T>
 T *ClassLoader::instantiateRaw(const std::string &class_name, const std::string &name) {
   std::lock_guard<std::mutex> lock(internal_mutex_);
-  auto factory_entry = loaded_factories_.find(class_name);
-  if (factory_entry != loaded_factories_.end()) {
-    auto obj = factory_entry->second->createRaw(name);
-    return dynamic_cast<T*>(obj);
-  } else {
-    return nullptr;
+  // allow subsequent classes to override functionality (like ProcessContextBuilder)
+  for (auto& child_loader : class_loaders_) {
+    if (auto* result = child_loader.second.instantiateRaw<T>(class_name, name)) {
+      return result;
+    }
   }
-}
-
-template<class T>
-T *ClassLoader::instantiateRaw(const std::string &class_name, const utils::Identifier& uuid) {
-  std::lock_guard<std::mutex> lock(internal_mutex_);
   auto factory_entry = loaded_factories_.find(class_name);
   if (factory_entry != loaded_factories_.end()) {
-    auto obj = factory_entry->second->createRaw(class_name, uuid);
+    auto obj = factory_entry->second->createRaw(name);
     return dynamic_cast<T*>(obj);
-  } else {
-    return nullptr;
   }
+  return nullptr;
 }
 
 }  // namespace core
diff --git a/libminifi/include/core/FlowConfiguration.h b/libminifi/include/core/FlowConfiguration.h
index 9211566..0c86b23 100644
--- a/libminifi/include/core/FlowConfiguration.h
+++ b/libminifi/include/core/FlowConfiguration.h
@@ -33,7 +33,6 @@
 #include "core/reporting/SiteToSiteProvenanceReportingTask.h"
 
 #include "core/Processor.h"
-#include "core/Resource.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
@@ -67,38 +66,10 @@ class FlowConfiguration : public CoreComponent {
    * Constructor that will be used for configuring
    * the flow controller.
    */
-  explicit FlowConfiguration(std::shared_ptr<core::Repository> /*repo*/, std::shared_ptr<core::Repository> flow_file_repo,
+  explicit FlowConfiguration(std::shared_ptr<core::Repository> repo, std::shared_ptr<core::Repository> flow_file_repo,
                              std::shared_ptr<core::ContentRepository> content_repo, std::shared_ptr<io::StreamFactory> stream_factory,
                              std::shared_ptr<Configure> configuration, const std::optional<std::string>& path,
-                             std::shared_ptr<utils::file::FileSystem> filesystem = std::make_shared<utils::file::FileSystem>())
-      : CoreComponent(core::getClassName<FlowConfiguration>()),
-        flow_file_repo_(std::move(flow_file_repo)),
-        content_repo_(std::move(content_repo)),
-        stream_factory_(std::move(stream_factory)),
-        configuration_(configuration),
-        filesystem_(std::move(filesystem)),
-        logger_(logging::LoggerFactory<FlowConfiguration>::getLogger()) {
-    controller_services_ = std::make_shared<core::controller::ControllerServiceMap>();
-    service_provider_ = std::make_shared<core::controller::StandardControllerServiceProvider>(controller_services_, nullptr, configuration);
-    std::string flowUrl = "", bucket_id = "default", flowId = "";
-    configuration->get(Configure::nifi_c2_flow_id, flowId);
-    configuration->get(Configure::nifi_c2_flow_url, flowUrl);
-    flow_version_ = std::make_shared<state::response::FlowVersion>(flowUrl, bucket_id, flowId);
-
-    if (!path) {
-      logger_->log_error("Configuration path is not specified.");
-    } else {
-      config_path_ = utils::file::PathUtils::canonicalize(*path);
-      if (!config_path_) {
-        logger_->log_error("Couldn't find config file \"%s\".", *path);
-        config_path_ = path;
-      }
-      checksum_calculator_.setFileLocation(*config_path_);
-    }
-
-    // it is okay if this has already been called
-    initialize_static_functions();
-  }
+                             std::shared_ptr<utils::file::FileSystem> filesystem = std::make_shared<utils::file::FileSystem>());
 
   ~FlowConfiguration() override;
 
@@ -151,30 +122,9 @@ class FlowConfiguration : public CoreComponent {
     return service_provider_;
   }
 
-  static bool add_static_func(std::string functor) {
-    std::lock_guard<std::mutex> lock(get_static_functions().atomic_initialization_);
-    get_static_functions().statics_sl_funcs_.push_back(functor);
-    return true;
-  }
-
-  static void initialize_static_functions() {
-    std::lock_guard<std::mutex> lock(get_static_functions().atomic_initialization_);
-    for (auto sl_func : get_static_functions().statics_sl_funcs_) {
-      core::ClassLoader::getDefaultClassLoader().registerResource("", sl_func);
-    }
-  }
-
   utils::ChecksumCalculator& getChecksumCalculator() { return checksum_calculator_; }
 
  protected:
-  void registerResource(const std::string &resource_function) {
-    core::ClassLoader::getDefaultClassLoader().registerResource("", resource_function);
-  }
-
-  void registerResource(const std::string &resource_location, const std::string &resource_function) {
-    core::ClassLoader::getDefaultClassLoader().registerResource(resource_location, resource_function);
-  }
-
   // service provider reference.
   std::shared_ptr<core::controller::StandardControllerServiceProvider> service_provider_;
   // based, shared controller service map.
diff --git a/libminifi/include/core/FlowFile.h b/libminifi/include/core/FlowFile.h
index 3ab0ed4..15a3b94 100644
--- a/libminifi/include/core/FlowFile.h
+++ b/libminifi/include/core/FlowFile.h
@@ -32,6 +32,7 @@
 #include "Connectable.h"
 #include "WeakReference.h"
 #include "utils/FlatMap.h"
+#include "utils/Export.h"
 
 namespace org {
 namespace apache {
@@ -294,23 +295,23 @@ class FlowFile : public CoreComponent, public ReferenceContainer {
 // FlowFile Attribute
 struct SpecialFlowAttribute {
   // The flowfile's path indicates the relative directory to which a FlowFile belongs and does not contain the filename
-  static const std::string PATH;
+  MINIFIAPI static const std::string PATH;
   // The flowfile's absolute path indicates the absolute directory to which a FlowFile belongs and does not contain the filename
-  static const std::string ABSOLUTE_PATH;
+  MINIFIAPI static const std::string ABSOLUTE_PATH;
   // The filename of the FlowFile. The filename should not contain any directory structure.
-  static const std::string FILENAME;
+  MINIFIAPI static const std::string FILENAME;
   // A unique UUID assigned to this FlowFile.
-  static const std::string UUID;
+  MINIFIAPI static const std::string UUID;
   // A numeric value indicating the FlowFile priority
-  static const std::string priority;
+  MINIFIAPI static const std::string priority;
   // The MIME Type of this FlowFile
-  static const std::string MIME_TYPE;
+  MINIFIAPI static const std::string MIME_TYPE;
   // Specifies the reason that a FlowFile is being discarded
-  static const std::string DISCARD_REASON;
+  MINIFIAPI static const std::string DISCARD_REASON;
   // Indicates an identifier other than the FlowFile's UUID that is known to refer to this FlowFile.
-  static const std::string ALTERNATE_IDENTIFIER;
+  MINIFIAPI static const std::string ALTERNATE_IDENTIFIER;
   // Flow identifier
-  static const std::string FLOW_ID;
+  MINIFIAPI static const std::string FLOW_ID;
 
   static const auto& getSpecialFlowAttributes() {
     static const std::array<std::string_view, 9> SPECIAL_FLOW_ATTRIBUTES {
diff --git a/libminifi/include/core/ObjectFactory.h b/libminifi/include/core/ObjectFactory.h
new file mode 100644
index 0000000..1f8010d
--- /dev/null
+++ b/libminifi/include/core/ObjectFactory.h
@@ -0,0 +1,149 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <memory>
+#include <utility>
+#include "Core.h"
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace core {
+
+/**
+ * Factory that is used as an interface for
+ * creating processors from shared objects.
+ */
+class ObjectFactory {
+ public:
+  explicit ObjectFactory(std::string group)
+      : group_(std::move(group)) {
+  }
+
+  ObjectFactory() = default;
+
+  /**
+   * Virtual destructor.
+   */
+  virtual ~ObjectFactory() = default;
+
+  /**
+   * Create a shared pointer to a new processor.
+   */
+  virtual std::shared_ptr<CoreComponent> create(const std::string& /*name*/) {
+    return nullptr;
+  }
+
+  /**
+   * Create a shared pointer to a new processor.
+   */
+  virtual CoreComponent *createRaw(const std::string& /*name*/) {
+    return nullptr;
+  }
+
+  /**
+   * Create a shared pointer to a new processor.
+   */
+  virtual std::shared_ptr<CoreComponent> create(const std::string& /*name*/, const utils::Identifier& /*uuid*/) {
+    return nullptr;
+  }
+
+  /**
+   * Create a shared pointer to a new processor.
+   */
+  virtual CoreComponent* createRaw(const std::string& /*name*/, const utils::Identifier& /*uuid*/) {
+    return nullptr;
+  }
+
+  virtual std::string getGroupName() const {
+    return group_;
+  }
+
+  virtual std::string getClassName() = 0;
+
+ private:
+  std::string group_;
+};
+/**
+ * Factory that is used as an interface for
+ * creating processors from shared objects.
+ */
+template<class T>
+class DefautObjectFactory : public ObjectFactory {
+ public:
+  DefautObjectFactory() {
+    className = core::getClassName<T>();
+  }
+
+  explicit DefautObjectFactory(std::string group_name)
+      : ObjectFactory(std::move(group_name)) {
+    className = core::getClassName<T>();
+  }
+
+  /**
+   * Create a shared pointer to a new processor.
+   */
+  std::shared_ptr<CoreComponent> create(const std::string &name) override {
+    std::shared_ptr<T> ptr = std::make_shared<T>(name);
+    return std::static_pointer_cast<CoreComponent>(ptr);
+  }
+
+  /**
+   * Create a shared pointer to a new processor.
+   */
+  std::shared_ptr<CoreComponent> create(const std::string &name, const utils::Identifier &uuid) override {
+    std::shared_ptr<T> ptr = std::make_shared<T>(name, uuid);
+    return std::static_pointer_cast<CoreComponent>(ptr);
+  }
+
+  /**
+   * Create a shared pointer to a new processor.
+   */
+  CoreComponent* createRaw(const std::string &name) override {
+    T *ptr = new T(name);
+    return dynamic_cast<CoreComponent*>(ptr);
+  }
+
+  /**
+   * Create a shared pointer to a new processor.
+   */
+  CoreComponent* createRaw(const std::string &name, const utils::Identifier &uuid) override {
+    T *ptr = new T(name, uuid);
+    return dynamic_cast<CoreComponent*>(ptr);
+  }
+
+  /**
+   * Gets the class name for the object
+   * @return class name for the processor.
+   */
+  std::string getClassName() override {
+    return className;
+  }
+
+ protected:
+  std::string className;
+};
+
+}  // namespace core
+}  // namespace minifi
+}  // namespace nifi
+}  // namespace apache
+}  // namespace org
diff --git a/libminifi/include/core/Resource.h b/libminifi/include/core/Resource.h
index a0ecb0d..9a650bf 100644
--- a/libminifi/include/core/Resource.h
+++ b/libminifi/include/core/Resource.h
@@ -20,6 +20,8 @@
... 4101 lines suppressed ...