Join conditions can now be specified in the metadata for each field
that is defined for a container. The ‘join-conditions’ tag is optional
for a field. If the 'join-conditions' tag is not specified, join
conditions are retrieved from the getJoinCondition and
getSubTableJoinConditions methods in the appropriate manager. Both methods of
retrieving join conditions can be used for a single xpath call. There is DEBUG logging that makes
it clear which of the methods of retrieving a join condition is being used.
When specified, the 'join-conditions' tag can contain an optional
context as well as 1 or more ‘join’ tags. The ‘join’ tag must contain a
foreign-column attribute as well as a local-column attribute. It can
optionally contain foreign-table and local-table attributes. Note that
the same tag is used to retrieve information for both joins and
sub-table joins.
The metadata joins framework makes use of a generic getFinalCondition
method defined in AbstractRPMObjectManager. This method appends the information retrieved from getFilter()
and then appends the type id condition. Unless getFinalCondition is overridden, the calling manager must implement method getContainerMap() or method getContainers().
Using a simple example, the database column name belonging to the container is specified using the local-column attribute. The column name belonging to the field is specified using the foreign-column attribute.
For example, the table associated with an AvailableWorkflowProcess is PROJECT_WKF_PROCESS. AvailableWorkflowProcess contains a field of type WorkflowProcess, whose data is stored in table TMT_WORKFLOW_CYCLES. In AvailableWorkflowProcess.xml, the field with name 'workflowProcess' is defined. The example below shows that the 'PROCESS_ID' column from the PROJECT_WKF_PROCESS table is specified using the local-column attribute. The 'ELEMENT_ID' column from the TMT_WORKFLOW_CYCLES table is specified using the foreign-column attribute.
<field name="workflowProcess" type="com.ibm.rpm.workflow.containers.WorkflowProcess" read-only-mode="always">
<documentation>
<![CDATA[The WorkflowProcess associated to the container. ]]>
</documentation>
<join-conditions>
<join foreign-column="ELEMENT_ID" local-column="PROCESS_ID"/>
</join-conditions>
</field>
Here is how this data used to be defined in the getJoinCondition method from the AvailableWorkflowProcessManager class:
else if (manager instanceof WorkflowManager)
{
// for xpath like: /AvailableWorkflowProcess[<condition>]/WorkflowProcess
joinCondition = JoinCondition.createSubSelect(
WorkflowManager.NAME_ELEMENT_ID, NAME_PROCESS_ID, TABLE_NAME,
container.getCondition());
}
The information from this example is used to generate a join like "/AvailableWorkflowProcess[<condition>]/WorkflowProcess" as well as a sub-table join like "/AvailableWorkflowProcess[WorkflowProcess[<condition>}]". This replaces the join condition specified in AvailableWorkflowProcessManager.getJoinCondition and the sub-table join condition in WorkflowManager.getSubTableJoinCondition.
The table names are retrieved using getTableName(String contextName) for the manager that belongs to the container and the field. If getTableName(String contextName) will not return the appropriate table name for either the container or the field, the table names must be specified using the local-table and/or foreign-table attributes. The example above could be replaced with:
<join-conditions>
<join foreign-column="ELEMENT_ID" foreign-table="TMT_WORKFLOW_CYCLES" local-column="PROCESS_ID" local-table="PROJECT_WKF_PROCESS"/>
</join-conditions>
This example (with or without the table names specified) will generate join condition:
TMT_WORKFLOW_CYCLES.ELEMENT_ID IN (SELECT PROJECT_WKF_PROCESS.PROCESS_ID FROM PROJECT_WKF_PROCESS)
It will generate sub-table join condition:
PROJECT_WKF_PROCESS.PROCESS_ID IN (SELECT TMT_WORKFLOW_CYCLES.ELEMENT_ID FROM TMT_WORKFLOW_CYCLES)
Multiple 'join' tags can be used within the 'join-conditions' tag in order to specify multiple sub-select statements.
The RunningWorkflowProcess container contains a field called workflowProcess. The table associated with a RunningWorkflowProcess is TMT_WORKFLOWS. RunningWorkflowProcess contains a field of type WorkflowProcess, whose data is stored in table TMT_WORKFLOW_CYCLES. The join condition for this field could be specified in the RunningWorkflowProcessManager as follows:
else if (manager instanceof WorkflowManager)
{
// for xpath like:
// /RunningWorkflowProcess[<condition>]/WorkflowProcess
joinCondition = JoinCondition.createSubSelect(
WorkflowManager.NAME_ELEMENT_ID,
WorkflowManager.NAME_PARENT_ID, WorkflowManager.TABLE_NAME,
container.getCondition());
joinCondition.appendWhere();
joinCondition.appendSubSelect(WorkflowManager.NAME_ELEMENT_ID,
NAME_WKF_DEF_ID, TABLE_NAME, container.getCondition());
}
The sub-table join condition would be specified in the WorkflowManager like this:
else if (manager instanceof RunningWorkflowProcessManager)
{
// for xpath like
// /RunningWorkflowProcess[WorkflowProcess[<condition>}]
joinCondition = new JoinCondition();
joinCondition.appendSubSelect(
RunningWorkflowProcessManager.NAME_WKF_DEF_ID, NAME_ELEMENT_ID,
TABLE_NAME, null);
joinCondition.appendWhere();
joinCondition.appendSubSelect(NAME_PARENT_ID, NAME_ELEMENT_ID,
TABLE_NAME, container.getCondition());
}
This same data is specified in RunningWorkflowProcess.xml for field workflowProcess. Note that the local-table attribute is required in this case because table TMT_WORKFLOW_CYCLES is not the table associated with container RunningWorkflowProcess.:
<join-conditions>
<join foreign-column="ELEMENT_ID" local-column="PARENT_ID" local-table="TMT_WORKFLOW_CYCLES"/>
<join foreign-column="ELEMENT_ID" local-column="WKF_DEF_ID"/>
</join-conditions>
This example will generate join condition:
TMT_WORKFLOW_CYCLES.ELEMENT_ID IN (
SELECT TMT_WORKFLOW_CYCLES.PARENT_ID FROM TMT_WORKFLOW_CYCLES WHERE TMT_WORKFLOW_CYCLES.ELEMENT_ID IN
(SELECT TMT_WORKFLOWS.WKF_DEF_ID FROM TMT_WORKFLOWS))
It will generate sub-table join condition:
TMT_WORKFLOWS.WKF_DEF_ID IN (
SELECT TMT_WORKFLOW_CYCLES.ELEMENT_ID FROM TMT_WORKFLOW_CYCLES WHERE TMT_WORKFLOW_CYCLES.PARENT_ID IN (
SELECT TMT_WORKFLOW_CYCLES.ELEMENT_ID FROM TMT_WORKFLOW_CYCLES))
If different join condition values are required for different contexts, a join conditions element can be specified for each context:
<join-conditions context="Document">
<join foreign-column="DOCUMENT_ID" local-column="PARENT_ID"/>
</join-conditions>
<join-conditions context="Resource">
<join foreign-column="RESOURCE_ID" local-column="PARENT_ID"/>
</join-conditions>
<join-conditions>
<join foreign-column="ELEMENT_ID" local-column="PARENT_ID"/>
</join-conditions>
The framework will select the join-conditions element with the appropriate context. If a join-conditions element with the required context is not specified in the metadata, the join-conditions element with a null context will be chosen if it exists.
When looking for a null-manager join condition, the framework will first check the calling manager's getJoinCondition method. If the null-manager join does not exist, it will call the generic getFinalCondition method. The getFinalCondition method can be overriden.