Prepare your Process for Phase Freeze

Preconditions and Rules

Preconditions

  • Process updates need to preserve the element identities. Do not use the “adopt elements” option when importing a core process.
  • The scope of the phase to freeze needs to be defined.
  • Children of a process element are paths of their parent and therefore must be part of the same phase as the parent element.
  • Metrics cannot be frozen, as they can have arbitrary data sources.
  • Roles cannot be frozen, as they are responsible for permission management and freezing them would prevent e.g. revoking permissions. However you can freeze a role association.
  • It is not possible to freeze process enactments.
  • Resources that are inlined in process element descriptions (e.g. images, arbitrary descriptions) are automatically frozen as long as they reside in the local process. Otherwise it is not ensured that the description of a frozen element remains unchanged.
  • It is not possible to freeze parts of a reference model.

Rules

  • The tailoring state of frozen elements cannot be modified any longer.
  • Freezing an element will also freeze the dependent project data like project attributes and files. For CM managed files, the referenced revision number is frozen.
  • Associations can be either frozen, converted to comments, or not frozen at all.
    • If an association is frozen, the source element will keep the exact amount of associations of that type. This might result in suppressing new associations at unfrozen elements in case the source and target element are not part of the same phase.
    • If an association is converted to a comment, the source element looks the same (apart from the comment has no link). This might result in deleting associations at the target element.
    • If an association is not frozen, the source element might get additional associations or it might lose some even if it is frozen itself.
  • Process elements that are part of multiple phases will get duplicated when one of those phases is frozen, as each phase needs a different version of the element. The duplicate is moved to an element folder called “Duplicaes for <phase name>”.
  • Frozen process elements are marked by a little check mark that provides a link to the owning phase.
  • Frozen core process elements are separated from the core process because they will not be updated anymore when the current valid version and the working revision are merged into a new valid version.
  • The process freeze operation will lock the process including the working revision and the valid version as long as the operation is running to ensure a consistent freeze result. This also means that only one freeze operation can be executed at a time in a single workspace.

Configure Phase Freeze Support in the Metamodel

Phase Freeze needs to be enabled in the process metamodel in Process.xml. There you have to specify which subtypes of which element represent the entity to be frozen (phase root). In a typical case, you want to freeze a phase of your process, but not milestones which are also of type phase. Additionally, a Stages Script file needs to be configured to collect all dependent elements of the frozen phase that should get frozen when the phase itself is frozen. (See example configuration below)

<processtype ident="...">
[...]
<element ident="phase" subtypes="phase
milestone" **freezableSubtypes="phase" freezeScript="local/freeze/
moduleSpec.js">**
<model>
[...]
</model>
<view>
[...]
</view>
</element>
[...]
</processtype>

Freeze Script Programming

The freeze script is used to determine the scope of the phase to freeze. It will call for an element of a freezable subtype and needs to collect all process elements that are part of that phase as well as all associations that need to get frozen. For all associations, it is possible to distinguish between freezing the association as is, or converting it to a comment. This is especially useful at the border of a phase or for associations of elements that are shared between phases. As shared elements are duplicated, freezing their associations as is would result in the target element to get associations to all copies, which might not be the desired behavior.

VariableTypeDescription
currentElementIBaseElementThe phase root element.
moduleElementSetSetThe result set to be filled with all elements to be frozen together with the current phase (currentElement).
moduleAssocSetSetThe result set to be filled with all associations to be frozen together with the current phase (currentElement).
moduleAssocToCommentSetSetThe result to be filed with all associations to be converted to comments when frozen together with the current phase (currentElement). It needs to be a subset of moduleAssocSet.
logLoggerA means to log messages to the Stages log file.

Example

The phase is here defined by the phase root element, its sequence associations and executed activities including their outputs. The responsible roles of the activities are converted to comments.

importPackage(Packages.java.util);
importPackage(Packages.de.methodpark.pkit.facade.impl);

function getSelfAndTransitiveChildren(self) {
var result = new Array();
result.push(self);
var children =
self.getEntities("hierarchy::hierarchic,targetrole=children");
for (var i = 0; i <children.length; ++i) {
result = result.concat(getSelfAndTransitiveChildren(children[i]));
}
return result;
}
function getAssociatedElementsCollectAssocs(source, assocType,
sourceRole, assocSet, remoteAssocSet) {
var assocSpec;
if (sourceRole === null) {
assocSpec = assocType;
} else {
assocSpec = assocType + ",sourcerole=" + sourceRole;
}
var assocsForward = source.getAssociations(assocSpec);
var targets = new Array();
for (var j = 0; j <assocsForward.length; j++) {
var forwardAssoc = assocsForward[j];
assocSet.add(forwardAssoc);
var isRemoteAssoc = forwardAssoc.isRemote();
//remote associations are converted to comments
if (isRemoteAssoc) {
remoteAssocSet.add(forwardAssoc);
}
var assocTarget = forwardAssoc.getTarget();
if (!(assocTarget instanceof MockElement)) {
// do not collect remote elements
if (!isRemoteAssoc) {
targets.push(assocTarget);
}
assocSet.add(forwardAssoc.getOpponentAssociation());
}
}
return targets;
}
function convertToComment(source, assocType, sourceRole, assocSet,
commentAssocSet) {
var assocSpec= assocType;
if (sourceRole !== null) {
assocSpec = assocSpec + ",sourcerole=" + sourceRole;
}
var assocsForward = source.getAssociations(assocSpec);
for (var j = 0; j <assocsForward.length; j++) {
var forwardAssoc = assocsForward[j];
assocSet.add(forwardAssoc);
commentAssocSet.add(forwardAssoc);
}
}
//start of script execution ----------------------------------
//freeze all children of the phase
var phases = getSelfAndTransitiveChildren(currentElement);
Collections.addAll(moduleElementSet, phases);
//freeze the predecessor and successor associations but not the
associated phases themselves
getAssociatedElementsCollectAssocs(currentElement, "sequence",
"predecessor", moduleAssocSet, moduleAssocToCommentSet);
getAssociatedElementsCollectAssocs(currentElement, "sequence",
"successor", moduleAssocSet, moduleAssocToCommentSet);
//freeze all the activities associated to one of the frozen phase
elements
var allActivities = new Array();
for (var k = 0; k <phases.length; k++) {
//Add associated 'execute' activities:
var associatedActivities = getAssociatedElementsCollectAssocs(phases[k],
"execute", null, moduleAssocSet, moduleAssocToCommentSet);
allActivities = allActivities.concat(associatedActivities);
}
Collections.addAll(moduleElementSet, allActivities);
var allOutputs = new Array();
for (var l = 0; l <allActivities.length; l++) {
//Freeze the output artifacts of the activities:
var outputs = getAssociatedElementsCollectAssocs(allActivities[l],
"output", null, moduleAssocSet, moduleAssocToCommentSet);
allOutputs = allOutputs.concat(outputs);
//convert responsible roles to comments
convertToComment(allActivities[l], "responsible", null, moduleAssocSet,
moduleAssocToCommentSet);
}
Collections.addAll(moduleElementSet, allOutputs);