Dynamic Dependency¶
IFS Application is a component-based soultion that provides organizations with the flexibility to select and integrate specific components according to their requirements. The combination of these chosen components forms a tailored solution set. There are more than 250 components, and when it comes to a solution set, each of these component would have static or dynamic dependencies on one another. If an IFS Client page needs to refer to an element located inside a dynamic component, the element should be annotated as a dependent element of a dynamic component.
Purpose of this document is to provide you with necessary tips and tricks on how to use Conditional Compilation to declare dynamic dependencies between components.
Solution Sets and Dynamic Dependency¶
Solution Set is a concept introduced in IFS Cloud being a simple configuration which defines what components should be enabled or disabled from the whole IFS component suite.
Being integrated with Developers Studio and Code Generation, any active Solution Set configuration will simply act as a filter and, show and/or Code Generate the enabled components and remove and/or not Code Generate the disabled components
The whole impact of a Solution Set definition is seen first when we start to code generate IFS Cloud. Components that are disabled (false) will not be shown in the Projects Navigator and therefore not being possible to code generate. For components that are enabled (true), there will also be a noticeable change during the code generation as the model files containing items marked with the DynamicComponentDependency attribute will check the component availability using the Solution Set definition. If the dependent component is disabled (or not listed in the SolutionSet), the result will be same as if the mentioned component was not physically available on disk. That means that the entire section below each DynamicComponentDependency annotation will be removed, not being part of the code generation.
Refer to Working with Solution Sets to get more information on deployment and installation properties of a component.
Components and Their Static or Dynamic Dependency¶
Components serve as containers that group entities, utilities, and enumerations into installable units, creating a logical framework for development. The interaction between these components occurs through 'Public' interfaces. In simpler terms, components act as holders, owning specific entities, enumerations, and utilities. This ownership role makes components a crucial foundation in the development process.
The Deploy.ini file is used to specify dependencies among components. These dependencies can be either static or dynamic
Static Dependency¶
When there is a Static Dependency between two components
Example: Component 1 has a Static Dependency with Component 2.
Then Component 1 cannot function without the purchasing / installation of Component 2.
Dynamic Dependency¶
When there is a Dynamic Dependency between two components
Example: Component 1 has a dynamic dependency with component 2.
Component 1 can function without Component 2, but the features in Component 1 that has dynamic dependencies with Component 2 will not work until Component 2 is purchased / installed.
Example: Dependency in a Deploy.ini file.
[Connections]
Invoic=STATIC
Apppay=DYNAMIC
Conmgt=DYNAMIC
Docman=DYNAMIC
Note: Refer to Component Deployment Profile File (deploy.ini) to get more information on deployment and installation properties of a component.
There are two recommended methodologies for articulating dynamic dependencies within the code of a component:
- Dynamic Component Dependency Annotation
and
- Conditional Compilation statements
While there are alternative approaches, such as:
-
Dynamic PL/SQL through DBMS_SQL
-
Running a dynamic statement using EXECUTE IMMEDIATE
these options should be approached with caution and generally avoided. The preferred and most efficient method is to leverage "Conditional Compilation."
Defining a Dynamic Dependency¶
A dynamic dependency has to be defined in two locations of a projection or client file. Namely:
- At the point of the element declaration or definition
- At the point where the element is referred.
The examples below show how these dependencies are created for each IFS Cloud Web model.
Example 1 - Dynamic component dependency in the projection model¶
At the point of declaration:
@Override
@DynamicComponentDependency PROJ
entity Activity {
crud = Read;
}
At the point of Reference:
@Override
entity Movie {
attribute Year Integer {
fetch = "Extract(year from RELEASE_DATE)";
}
array Cast(MovieId) to MovieActor(MovieId);
@DynamicComponentDependency PROJ
reference Movie(MovieId) to Activity(ActivityId);
}
Example 2 - Dynamic component dependency in the client model¶
At the point of Definition:
@DynamicComponentDependency PROJ
group MovieGroupWithProjectInfo for MovieWithProjQry {
label = "Movie";
field MovieId;
field Title;
field Genre;
field ReleaseDate;
field Rating {
rating {
maxrating = 10;
showlabel = true;
}
}
field Country;
}
At the point of Reference:
page MovieDetail using Movies {
label = "${TitleYear}";
stateindicator MovieStateIndicator;
selector MovieSelector;
@DynamicComponentDependency PROJ
group MovieGroupWithProjectInfo;
list MovieCast(Cast) bind MovieSelector;
}
Example 3 - Using a Dynamic Fragment¶
If you are using a dynamic fragment, annotate it with @DynamicComponentDependency
when you include it in the projection or client file.
@DynamicComponentDependency ORDER
include fragment SomeFragmentFromOrder;
NOTE: When you are referring items in the dynamic fragment always remember to annotate them as well.
What is Conditional Compilation¶
Conditional compilation in PL/SQL is a feature that allows you to selectively include or exclude sections within a component code during compilation based on certain conditions. This is particularly useful for writing code that can be customized or adapted for different environments or scenarios
Below is an example of PL/SQL code with Conditional Compilation:
$IF boolean_static_expression $THEN
some pl/sql code
$ELSE
other pl/sql code
$END
Additional information regarding Conditional Compilation can be found in the Oracle documentation.
How to format Conditional Compilation¶
Conditional Compilation code can be used anywhere within a PL/SQL code and it always comes in between
- $IF (at the start)
and
- $END(at the end)
keywords.
WHILE (Client_SYS.Get_Next_From_Attr(attr_, ptr_, name_, value_)) LOOP
IF (name_ = 'ITEM_ID') THEN
newrec_.item_id := value_;
Todo_Item_API.Exist(newrec_.item_id);
ELSIF (name_ = 'PERSON_ID') THEN
newrec_.person_id := value_;
$IF Component_Enterp_SYS.INSTALLED $THEN
Person_Info_API.Exist(newrec_.person_id);
$ELSE
NULL;
$END
ELSE
Error_SYS.Item_Not_Exist(lu_name_, name_, value_);
END IF;
END LOOP;
Using Conditional Compilation in Views¶
It is not possible to use Conditional Compilation when creating views in Oracle, but sometimes dynamically built views are needed while developing IFS Applications. The framework has therefore added support for having Conditional Compilation in views.
When views with a conditional compilation are generated from .views files into deployable code, it is done in both. apv files and the method Post_Installation_View in the .apy file. In the .apv, it is deployed with Conditional Compilation, meaning only parts of the view that are available at deployment time will be included in the dynamic statement. The Post_Installation_View methods are executed after all components are deployed in the database, meaning that the parts of the view that are available in the database will be included. This means that the view must have the exact same interface no matter of the dynamic statements are true or false.
Installation Process and Component Management in IFS Application Framework¶
When the IFS Application installed to clients local server:
- IFS Application Framework creates packages named as:
Component_<component name>_SYS
(Ex:Component_Enterp_SYS
)
for all the components related to client installation.
-
Each package consists of information related to a component such as, whether the component is installed in the database or not.
-
In addition to the packages created for related components, Framework also create packages for dynamically used components.
-
In the beginning of an installation, all component constants are set to
FALSE
(Note: Except for the components that has already being installed and are not part of the delivery)
- At the end of the installation process, constants are transitioned to
TRUE
for the installed components, while the remaining components retain a status ofFALSE
. This transition of constants has implications for the status of database objects. Subsequently, all the invalid database objects undergo recompilation.
Note: Please be aware that it is possible for a component to have a conditional compilation set to itself. This can be useful if an object used in a package is created as a Post Installation Object. Normally its views, that are defined differently depending on which other components are installed, that are created as Post Installation Objects.
- Information related to installed or not-installed components are stored in Module entity. Dynamic dependencies are retrieved from the deploy.ini files and stored in ModuleDependency entity. Therefor it is crucial to mention all the Conditional Compilation Component packages in the code of deploy.ini as Dynamic.
- This means that all usages of the Conditional Compilation component packages in the code must be reflected as a DYNAMIC connection in the deploy.ini. This is also the case when a component refers to itself.
Example : deploy.ini
[Connections]
Invoic=STATIC
Apppay=DYNAMIC
Conmgt=DYNAMIC
Docman=DYNAMIC
Example: Generated code in Install.tem
-- The CompRegAndDep.sql is generated automatically in the build process
START CompRegAndDep.sql
EXEC Installation_SYS.Create_Component_Package(FALSE);
...
[installing components]
...
EXEC Installation_SYS.Create_Component_Package(TRUE);
EXEC Database_SYS.Compile_All_Invalid_Objects;
...
Example : Generated Package (Component_<component name>_SYS)
CREATE OR REPLACE PACKAGE Component_Enterp_SYS IS
module_ CONSTANT VARCHAR2(25) := 'FNDBAS';
lu_name_ CONSTANT VARCHAR2(25) := 'ComponentEnterp';
lu_type_ CONSTANT VARCHAR2(14) := 'System Service';
-------------------------------------------------------------------------
-------------------- LU SPECIFIC GLOBAL VARIABLES -----------------------
-------------------------------------------------------------------------
-------------------------------------------------------------------------
-------------------- INSTALLED COMPONENTS -------------------------------
-------------------------------------------------------------------------
INSTALLED CONSTANT BOOLEAN := TRUE;
END Component_Enterp_SYS;
Through the utilization of conditional compilation statements, a package (Component_<component name>_SYS) and its global constants can be used to execute specific code depending on whether the component is installed or not. In other words the compilation code varies depending on the Boolean value of the component constant (TRUE / FALSE), which generates more efficient code compiled into the database.
Example: Conditional Compilation Statement
$IF Component_Enterp_SYS.INSTALLED $THEN
Person_Info_API.Exist(newrec_.person_id);
$ELSE
NULL;
$END
This gives the opportunity to get rid of old dynamic PL/SQL code which executes at a considerably slower rate than the compiled code.
If a package (Component_<component name>_SYS) is missing from a development environment, there is a shortcut to temporary add it until the next build is executed.
First you must insert the dependency, then call the procedure that generates the package.
INSERT INTO module_dependency_tab
(module, dependent_module, dependency, rowversion)
VALUES
('<my component>', '<dynamic component>', 'DYNAMIC', SYSDATE);
COMMIT;
BEGIN
Installation_SYS.Create_Component_Package(TRUE);
END;
/
Developer Studio usages of Conditional Compilation¶
If you want an entire PL/SQL method to be excluded or included depending on another component, use the @DynamicComponentDependency annotation.
But it is strongly recommended to limit the usage of this annotation exclusively to implementation methods.
Placing it within methods published in the package specification may result in deployment errors and significantly impede build time. Alternatively, a similar outcome can be accomplished by utilizing a static Boolean expression of your own with the @DynamicDependency annotation.
Dynamic elements can exist in both the projection and client model as well as in fragments.
Dynamic Elements in Client | Dynamic Elements in Projection |
---|---|
1. Navigator entries | 1. Entity Sets |
2. Sub-Menus | 2. Entities |
3. Pages | 3. Queries |
4. Groups | 4. Summaries |
5. Lists | 5. References |
6. Tabs | 6. Functions |
7. Pages | 7. Actions |
8. Commands | |
9. Fields | |
10. List of Values | |
11. Selectors | |
12. List of Value Lists | |
Static Code Analyzer Tool and Dynamic Dependency¶
Static Code Analyzer (SCA) examines source code before the code is generated and deployed. This is done by analyzing a set of code against a set of coding rules. With Static Code Analysis, developers get to know early on if there are any problems in their code. One of the rules available in Static Code Analyzer is "DependencyAnnotation", which checks the dependency among components. DependencyAnnotation annotation helps to analyze whether to access the code in optional components or not. If the annotation is missing in the code where the optional code is used, SCA tool warns developers about the missing annotation and it helps to avoid runtime and deployment issues.
When conditional compilation statement is added, but if the Static or Dynamic entry is missing in depoly.ini file, SCA will raise an error about missing declaration in deploy.ini file.
Refer to Static Code Analyzer to get more information on deployment and installation properties of a component.
Developer Studio and Conditional Compilation¶
Static Code Analyzer (SCA) is capable to identifying missing conditional compilation statements in the code, as missing such statements would lead to runtime and deployment issues.
Detection of conditional compilation errors is often deferred until central builds, as only the "true" code undergoes deployment and testing during development. Typically, the $IF block is examined while the $ELSIF or $ELSE blocks are overlooked, resulting in compilation errors during customer configurations. Early identification of such issues during development is highly advantageous, providing valuable feedback and minimizing the likelihood of complications during subsequent stages.
The newly introduced Test Conditional Compilation context menu item lets you compile the $ELSIF and $ELSE blocks, which otherwise would not be compiled during the usual deployment. You will find this context menu item by right-clicking in the editor of *plsql*/*plsvc*/views files.
Benefits of Conditional Compilation¶
Conditional Compilation presents advantages compared to alternative solutions that require a different implementation approach. Some examples of these benefits are as follows:
- Better performance (compared to Using Dynamic PL/SQL through DBMS_SQL)
Compiled code always performs better than dynamic code. - Easier implementation (compared to a solution with stub packages, with or without any implementation)
Just add a simple Conditional Compilation piece of code and you have finished your solution. Also there are no maintenance problems in the future. - Easier testing
By amending a Boolean value in a package then you can test both of your cases very easily without the need to deploy/uninstall a component.
Drawback
- Code needs to be recompiled when a Boolean constant is changed.
Important: It is important to manage changes to Boolean constants carefully. Sometimes it is necessary to recompile the code, but in the majority of cases, the code will automatically recompile when needed. In a production environment at a customer's site, it is advisable to modify the Boolean package constants only during installation or upgrade procedures to avoid potential disruptions.
Applications of Conditional Compilation Across Other Domains¶
In addition to checking whether a component is installed or not, there are many other places where Conditional compilation can be very useful. Below you can see some of these examples:
- Tracing
You can add trace texts that are only visible if you set a flag in a specific package. Alternatively you can insert specific data into tables so you can see what happened during the execution of your code. This avoids performance impacts on the code within a production environment. - Oracle Versions
You can add code that behaves differently depending on which version of Oracle you are running. The packageDbms_Db_Version
holds information about which version you are running on. - Oracle Features
If you have a specific Oracle feature installed you could compile the code so it becomes optional as to whether this feature is used or not.