Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [0.10.7] - Unreleased

### Added
- #1141: New `Production` resource processor that allows managing auto-start and auto-update of interoperability productions.
- #1141: New `DecomposedProduction` resource processor for managing an interoperability production class constituted from PTD files.
- #408: Modules can now list dependencies without specifying version; will be assumed to be "*"
- #992: Implement automatic history purge logic
- #973: Enables CORS and JWT configuration for WebApplications in module.xml
Expand Down
143 changes: 143 additions & 0 deletions src/cls/IPM/ResourceProcessor/DecomposedProduction.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/// Resource processor for IRIS Interoperability productions stored as decomposed PTD files.
/// The production class is fully constituted by importing PTD files from the ptd/ subdirectory.
Class %IPM.ResourceProcessor.DecomposedProduction Extends %IPM.ResourceProcessor.Abstract
{

Parameter DESCRIPTION As STRING = "Manages an IRIS Interoperability production class constituted from PTD files in the ptd/ subdirectory.";

Parameter ATTRIBUTES As STRING = "Name";

/// The class name of the production to manage.
Property Name As %String(MAXLEN = "") [ Required ];

ClassMethod IsSupported() As %Boolean
{
quit ##class(%Dictionary.ClassDefinition).%ExistsId("%Studio.SourceControl.Production")
}

Method OnGetUniqueName(Output pUniqueName)
{
set pUniqueName = ..Name _ ".CLS"
}

Method OnBeforePhase(
pPhase As %String,
ByRef pParams) As %Status
{
set sc = $$$OK
try {
set sc = ##super(pPhase, .pParams)
if $$$ISERR(sc) {
quit
}

if (pPhase = "Validate") {
set sysReqs = ..ResourceReference.Module.SystemRequirements
if '$isobject(sysReqs) || (sysReqs.Interoperability '= "enabled") {
set sc = $$$ERROR($$$GeneralError, $$$FormatText("Module '%1' must declare Interoperability in SystemRequirements to use the DecomposedProduction resource processor.", ..ResourceReference.Module.Name))
quit
}

if '##class(%IPM.ResourceProcessor.DecomposedProduction).IsSupported() {
set sc = $$$ERROR($$$GeneralError, "DecomposedProduction resource processor is not supported on this InterSystems IRIS version.")
quit
}
}
} catch ex {
set sc = ex.AsStatus()
}
quit sc
}

Method OnAfterPhase(
pPhase As %String,
ByRef pParams) As %Status
{
set sc = $$$OK
try {
set sc = ##super(pPhase, .pParams)
if $$$ISERR(sc) {
quit
}

if (pPhase = "Compile") {
// See %Studio.SourceControl.Production for details on how decomposed productions are represented on the file system
set ptdDir = ..ResourceReference.Module.Root _ "ptd/" _ $translate(..Name, ".", "_") _ "/"
set sc = ##class(%Studio.SourceControl.Production).ImportPTDsDir(ptdDir)
if $$$ISERR(sc) {
quit
}
}
} catch ex {
set sc = ex.AsStatus()
}
quit sc
}

Method OnResolveChildren(
ByRef pResourceArray,
pCheckModuleOwnership As %Boolean) As %Status
{
// the production class itself should NOT be controlled by another package resource
set pResourceArray(..Name _ ".CLS") = ""
quit $$$OK
}

Method OnBeforeArtifact(
pExportDirectory As %String,
pWorkingDirectory As %String,
ByRef pParams) As %Status
{
set sc = $$$OK
try {
if (pExportDirectory = pWorkingDirectory) {
quit
}

if '..ResourceReference.Deploy {
set subDir = "ptd/" _ $translate(..Name, ".", "_") _ "/"
set sc = ##class(%IPM.Utils.File).CopyDir(
pExportDirectory _ subDir,
pWorkingDirectory _ subDir)
}
} catch ex {
set sc = ex.AsStatus()
}
quit sc
}

Method OnPhase(
pPhase As %String,
ByRef pParams,
Output pResourceHandled As %Boolean = 0) As %Status
{
set sc = $$$OK
try {
if (pPhase = "Clean") {
set pResourceHandled = 1

set sc = ##class(Ens.Director).GetProductionStatus(.runningName, .state)
if $$$ISERR(sc) {
quit
}

if (state '= 0) && (runningName = ..Name) {
set timeout = ##class(Ens.Director).GetRunningProductionShutdownTimeout()
set sc = ##class(Ens.Director).StopProduction(timeout)
if $$$ISERR(sc) {
quit
}
}

set sc = ##class(Ens.Director).DeleteProduction(..Name)
if $$$ISERR(sc) {
quit
}
}
} catch ex {
set sc = ex.AsStatus()
}
quit sc
}

}
149 changes: 149 additions & 0 deletions src/cls/IPM/ResourceProcessor/Production.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/// Resource processor for IRIS Interoperability productions.
/// Manages runtime state: autostart registration, auto-update on activate, and stop on uninstall.
Class %IPM.ResourceProcessor.Production Extends %IPM.ResourceProcessor.Abstract
{

Parameter DESCRIPTION As STRING = "Manages the runtime lifecycle of an IRIS Interoperability production: autostart, auto-update on activate, and stopping on uninstall.";

Parameter ATTRIBUTES As STRING = "Name,AutoStart,AutoUpdate";

/// The class name of the production to manage.
Property Name As %String(MAXLEN = "") [ Required ];

/// If true, registers this production as the namespace autostart production and starts it during Activate.
Property AutoStart As %Boolean [ InitialExpression = 0 ];

/// If true, queues an update if the production needs updating during Activate.
Property AutoUpdate As %Boolean [ InitialExpression = 1 ];

Method OnGetUniqueName(Output pUniqueName)
{
// an arbitrary extension chosen not to collide with future document types
set pUniqueName = ..Name _ ".ZPRODUCTION"
}

Method OnBeforePhase(
pPhase As %String,
ByRef pParams) As %Status
{
set sc = $$$OK
try {
set sc = ##super(pPhase, .pParams)
if $$$ISERR(sc) {
quit
}

if (pPhase = "Validate") {
set sysReqs = ..ResourceReference.Module.SystemRequirements
if '$isobject(sysReqs) || (sysReqs.Interoperability '= "enabled") {
set sc = $$$ERROR($$$GeneralError, $$$FormatText("Module '%1' must declare <SystemRequirements Interoperability=""enabled""/> to use the Production resource processor.", ..ResourceReference.Module.Name))
quit
}
}
} catch ex {
set sc = ex.AsStatus()
}
quit sc
}

Method OnAfterPhase(
pPhase As %String,
ByRef pParams) As %Status
{
set sc = $$$OK
try {
set sc = ##super(pPhase, .pParams)
if $$$ISERR(sc) {
quit
}

if (pPhase = "Activate") {
if ..AutoStart {
// Set this production as the namespace autostart production
set sc = ##class(Ens.Director).SetAutoStart(..Name)
if $$$ISERR(sc) {
quit
}

set sc = ##class(Ens.Director).GetProductionStatus(.runningName, .state)
if $$$ISERR(sc) {
quit
}

if state = 0 {
// StartProduction issues transaction control statements that break
// IPM's outer transaction, so run it in a worker job
set workmgr = $system.WorkMgr.%New()
if workmgr = "" {
set sc = %objlasterror
quit
}
set sc = workmgr.Queue("##class(Ens.Director).StartProduction", ..Name)
if $$$ISERR(sc) {
quit
}
set sc = workmgr.Sync()
if $$$ISERR(sc) {
quit
}
}
}

if ..AutoUpdate {
if ##class(Ens.Director).ProductionNeedsUpdate() {
set timeout = ##class(Ens.Director).GetRunningProductionUpdateTimeout()
set workmgr = $system.WorkMgr.%New()
if workmgr = "" {
set sc = %objlasterror
quit
}
set sc = workmgr.Queue("##class(Ens.Director).UpdateProduction", timeout)
if $$$ISERR(sc) {
quit
}
}
}
}
} catch ex {
set sc = ex.AsStatus()
}
quit sc
}

Method OnPhase(
pPhase As %String,
ByRef pParams,
Output pResourceHandled As %Boolean = 0) As %Status
{
set sc = $$$OK
try {
if (pPhase = "Clean") {
set pResourceHandled = 1

set sc = ##class(Ens.Director).GetProductionStatus(.runningName, .state)
if $$$ISERR(sc) {
quit
}

if (state '= 0) && (runningName = ..Name) {
set timeout = ##class(Ens.Director).GetRunningProductionShutdownTimeout()
set sc = ##class(Ens.Director).StopProduction(timeout)
if $$$ISERR(sc) {
quit
}
}

if ..AutoStart {
set sc = ##class(Ens.Director).SetAutoStart("")
if $$$ISERR(sc) {
quit
}
}
}
} catch ex {
set sc = ex.AsStatus()
}
quit sc
}

}
Loading
Loading