Difference between revisions of "Modularity Concepts"

From InfiniteERP Wiki
Jump to: navigation, search
(Created page with "== Overview == Openbravo 2.50 came with the new concept of ''Modularity'': the ability for developers to build, package and distribute ''Extension Modules'' and for users to...")
 
(Update Modularity Concepts dari Etendo Documentation versi terbaru, rebrand Etendo→InfiniteERP)
 
Line 1: Line 1:
== Overview ==
+
{{Languages}}
 +
{{BackTo|Main Page}}
  
Openbravo 2.50 came with the new concept of ''Modularity'': the ability for developers to build, package and distribute ''Extension Modules'' and for users to install, uninstall and update ''Extension Modules''.
+
= Modularity Concepts =
  
An ''Extension Module'' is a piece of additional functionality that can be deployed optionally and independently on top of Openbravo ERP. Examples of modules are: additional reports, additional windows, connectors, content packs (translations, chart of accounts, list of tax codes, product categories, etc).
+
This document contains an overview of the process of developing InfiniteERP Modules. It describes the concepts, artifacts and processes involved in building, packaging and distributing modules for InfiniteERP.
  
The objectives of modularity are:
+
== Overview ==
*Making it easier to contribute to Openbravo ERP by allowing distributed and decoupled development and maintenance of optional features.
 
*Providing the Community with a rich set of extensions to meet their unique business requirements without bloating the core product.
 
*Shorten the implementation cycles by enabling system integrators to develop micro-vertical templates.
 
  
This document contains an overview of the process of developing Openbravo ERP Modules.
+
InfiniteERP supports the concept of '''Modularity''': the ability for developers to build, package and distribute '''Extension Modules''', and for users to install, uninstall and update '''Extension Modules'''.
  
== Before you start ==
+
An '''Extension Module''' is a piece of additional functionality that can be deployed optionally and independently on top of InfiniteERP. Examples of modules are: additional reports, additional windows, connectors, content packs (translations, chart of accounts, list of tax codes, product categories, etc).
  
 +
The objectives of modularity are:
  
 +
* Making it easier to contribute to InfiniteERP by allowing distributed and decoupled development and maintenance of optional features
 +
* Providing the Community with a rich set of extensions to meet their unique business requirements without bloating the core product
 +
* Shortening the implementation cycles by enabling system integrators to develop micro-vertical templates
  
=== Configure your instance ===
+
== Concepts ==
Please review the [http://wiki.openbravo.com/wiki/Development_Stack_Setup Development Stack Setup] documentation before going ahead.
 
 
 
=== Concepts ===
 
Before you start it's also required to understand some new concepts. These concepts are described in detail in following sections in this document.
 
 
 
==== Types of Extension Modules ====
 
 
 
There are three types of ''Extension Modules'':
 
* '''Modules''': Base content container. Within a ''Module'' you can include all types of artifacts but ''Configuration Scripts'': Application Dictionary components, Software resources and Reference data. ''Modules'' are the way to add new elements to Openbravo ERP. In a ''Module'' you cannot modify elements of other modules -including core-. The reason of that is to avoid crossed dependencies between them.
 
* '''Packs''':  a ''Pack'' is a collection of modules and no more. They are intended to simplify deployment and to encourage fine grained modules. Special packs are localization and verticalization packs.
 
* '''Templates''': a combination of a ''Pack'' and a ''configuration script'' that is able to modify the behavior of AD components in ''Modules'' included in the ''Pack''.
 
  
The three of them are generically referred as ''Modules''.
+
Before you start, it is required to understand some concepts. These concepts are described in detail in the following sections.
  
==== Artifacts in an Extension Module ====
+
=== Types of Extension Modules ===
  
There are four types of artifacts that can be included in an ''Extension Module'':
+
There are three types of '''Extension Modules''':
* '''Application Dictionary components''': Metadata that describe Openbravo ERP such as Windows, Tabs, Fields, Messages, etc.
 
* '''Software Resources''': Openbravo ERP components not expressed as metadata such as xml definition of database schema objects, java classes, jar libraries, XML files, etc.
 
* '''Reference Data''': Business information referred by transactions and that tend not to change frequently such as Charts of accounts, tax codes, banks, product categories, etc. They can be defined at system, client or organization level.
 
* '''Configuration Script''': Changes in Application Dictionary Components applied to other modules to support a specific set of business processes, such as Hide / show tabs or fields, replace standard processes, etc. Only meaningful changes are allowed.
 
  
Openbravo platform itself can not be modified through modules. In particular you are not allowed to modify wad (src-wad code) in a module. It should not be a limitation since the platform is designed to be extensible.
+
* '''Modules''': Base content container. Within a '''Module''', you can include all types of artifacts but '''Configuration Scripts''': Application Dictionary components, Software Resources and Reference Data. '''Modules''' are the way to add new elements to InfiniteERP. In a '''Module''', you cannot modify elements of other modules — including core. The reason for that is to avoid cross-dependencies between them.
 +
* '''Bundle''': a '''Bundle''' is a collection of modules and no more. They are intended to simplify deployment and to encourage fine-grained modules. Special bundles are localization and verticalization bundles.
 +
* '''Templates''': a combination of a '''Module''' and a '''Configuration Script''' that is able to modify the behavior of AD components in '''Modules'''.
  
==== Packaging and .obx files ====
+
The three of them are generically referred to as '''Modules'''.
  
All the content of a module -code, utility files, data- is contained in a separate folder for each module. All the content in that folder is related to and only related to that module. There is a folder within the main Openbravo folder called ''modules'' where all the modules that you have installed or developed are located. For each module there is a folder identified by the java package of the module. In that folder the source code structure of openbravo (config, src, src-db, lib, etc.) is replicated as required to store the content of the module.
+
=== Artifacts in an Extension Module ===
  
 +
There are four types of artifacts that can be included in an '''Extension Module''':
  
Modules are distributed as .obx files which are compressed files of the module folder. You can directly decompress it using a zip tool to browse its content.
+
* '''Application Dictionary Components''': Metadata that describes InfiniteERP such as Windows, Tabs, Fields, Messages, etc.
 +
* '''Software Resources''': InfiniteERP components not expressed as metadata such as `XML` definition of database schema objects, Java classes, XML files, etc.
 +
* '''Reference Data''': Business information referred by transactions and that tend not to change frequently such as ''Charts of accounts'', ''tax codes'', ''banks'', ''product categories'', etc. They can be defined at system, client or organization level.
 +
* '''Configuration Script''': Changes in ''Application Dictionary Components'' applied to other modules to support a specific set of business processes, such as '''hide / show''' tabs or fields, replace standard processes, etc. Only meaningful changes are allowed.
  
 +
The InfiniteERP platform itself cannot be modified through modules. In particular, you are not allowed to modify WAD (<code>src-wad</code> code) in a module. It should not be a limitation since the platform is designed to be extensible.
  
[[Image:ModulePackaging.png]]
+
=== Packaging and .zip and .jar Files ===
  
==== Module Management Console (MMC) ====
+
All the content of a module — code, utility files, data — is contained in a separate folder for each module. All the content in that folder is related to, and only related to, that module. There is a folder within the main InfiniteERP folder called '''modules''' where all the modules that you have installed or developed are located. For each module there is a folder identified by the Java package of the module. In that folder the source code structure of InfiniteERP (<code>config</code>, <code>src</code>, <code>src-db</code>, <code>lib</code>, etc.) is replicated as required to store the content of the module.
  
This is a window in Openbravo ERP where System administrators can see installed ''Extension modules'' in their instances, and where they can install new ones and uninstall or update the ones that are already installed.
+
Modules are distributed as <code>.zip</code> or <code>.jar</code> files which are compressed files of the module folder.
  
You can find more detailed information about how to operate MMC in the [[Modules_Management | Modules Management document]]
+
=== InfiniteERP Repository ===
  
[[Image:ModuleManagement1_ob3.png|700px|center]]
+
Supported InfiniteERP modules are published as packages. Licensed developers and partners with access can browse and download packages available there.
  
[[Image:ModuleManagement2_ob3.png|700px|center]]
+
More information about module publishing can be found in [[How to publish a Module|How to Publish a Module]].
  
==== Central Repository ====
+
== Introduction to the Process of Developing a Module ==
  
The Central Repository is a system embedded in the Openbravo Forge to provide services related to Openbravo ERP ''Modules'' for developers and users. Detailed description about Central Repository can be found in [[How_to_publish_a_Module#Central_Repository | Publishing Modules document]].
+
The process of developing a Module has three main steps:
  
== Introduction to the process of developing a Module ==
+
1. '''Register''' your Module in the Application Dictionary
The process of developing a Module has three main steps:
+
2. '''Develop''' the artifacts included in your Module. Depending on the functional specification and technical design of your module it might include only one type of artifacts or a combination of them. In the following sections each type of artifact is described in detail.
# '''Register''' your Module in the Application Dictionary and in the Central Repository.
 
# '''Develop''' the artifacts included in your Module. Depending on the functional specification and technical design of your module it might include only one type of artifacts or a combination of them. In following sections each type of artifact is described in detail.
 
# '''Package''' your module into an .obx file, and '''publish''' it in the Central Repository.
 
  
Steps 1 and 3 are common to all types of modules and straightforward. Step 2 depends on the requirements of your module. It has not significantly changed from the way you have developed Openbravo ERP code in previous releases to 2.50 but a few details that you need to know and that are described throughout later in this document. In particular the development tasks (create/update the database, build and compile the system, etc.) have been lightly modified to fit the Modularity paradigm.  
+
Step 1 is common to all types of modules. Step 2 depends on the requirements of your module. It has not significantly changed from the way you have developed InfiniteERP code in previous releases.
  
Be aware that from now on every piece of Openbravo ERP code belongs to a module (you can see for example that the Openbravo distribution in fact includes several modules, and one of them is "Core"). You should do all your new developments through modules, including your customizations. Still you can do changes directly in other modules -including Openbravo ERP core- but it is highly recommended not to do that. Maintenance will be dramatically better if you keep your changes isolated by doing them through modules, as you can update individual modules without doing any changes to other ones (so for example you can update the Openbravo distribution modules, without doing any changes to your modules).
+
Be aware that from now on every piece of InfiniteERP code belongs to a module (you can see, for example, that the InfiniteERP distribution in fact includes several modules, and one of them is '''Core'''). You should do all your new developments through modules, including your customizations. Still you can do changes directly in other modules including InfiniteERP core but it is highly recommended not to do that. Maintenance will be dramatically better if you keep your changes isolated by doing them through modules, as you can update individual modules without doing any changes to other ones (so, for example, you can update the InfiniteERP distribution modules without doing any changes to your modules).
  
Following sections will describe each step in detail.
+
=== Register a Module ===
  
== Register a Module ==
 
 
The first thing you have to do is to create a new Module entry in the Module Window within the Application Dictionary menu folder.
 
The first thing you have to do is to create a new Module entry in the Module Window within the Application Dictionary menu folder.
 
[[Image:ModuleWindow_ob3.png]]
 
  
 
There are some details that you need to be aware of:
 
There are some details that you need to be aware of:
* Each module has its own native (base) ''language''. In following sections the translation process is described, by now just choose the language you prefer to develop the UI of your module. Of course if you choose English it will be easier to disseminate (eg. to find people to translate it to other languages).
 
* ''Name'', ''description'' and ''help'' are the properties used to explain in the Central Repository what your module is. Write them in natural style using the native language you have chosen.
 
* The ''Version Number'' is composed by three numbers separated by two dots to match the [http://wiki.openbravo.com/wiki/Openbravo_Releases#Understanding_Version_Numbers:_the_Life_Cycle_of_a_Community_Edition Openbravo template] for version numbers. In this field you need to have the current version you are working on (there might be multiple versions of your module). Later in this document [[#Version_numbers_and_how_dependencies_and_includes_are_managed | Version Numbers]] are explained in detail.
 
* The ''java package'' is a unique identifier of your module and has to match the Java packaging names rules as described in the Java spec. ([http://java.sun.com/docs/books/jls/third_edition/html/names.html names] and [http://java.sun.com/docs/books/jls/third_edition/html/names.html#6.8.1 package names]). You need to carefully set this value because you are not allowed to change it once your module is registered in the Central Repository. If your module includes java files they have to be packaged within your module java package or in subpackages within it. Examples of java packages for a module are com.yourcompany.yourPackage, org.yourfoundation.yourPackage.yourSubpackage, etc. You will notice that modules released by Openbravo start by org.openbravo. You should name your modules with a Java package which doesn't start by org.openbravo, but with an identifier of you, your company, or the project you belong to.
 
* Choose the type (Module, Pack, Template) as described in the Concepts section
 
* In development is a boolean property to let the system know that you are developing on that module. Only modules ''in development'' will be exported by development tools and the System will raise an error if you try to modify some component on a module that is not in development
 
* Although you might have more than one module in development you can set which one is choosen by ''default'' when developing. This is just a way to set a default value for the module when you edit the Application Dictionary
 
{{(!)| Starting from '''PR18Q3''', it is recommended to restart the instance after changing the development status of a module in order to update cache's status. Also note that production instances cannot have modules in "In development" status. }}
 
* Some modules will not have UI (eg. a connector to a banking system or a web service) so there is no need to translate them
 
* If your module is a ''translation module'' of another module you have to check this flag to allow users to search for translations. Later in this document there is a full description of how to create a [[#Translations | translation]] module.
 
* If your module has ''Chart of accounts'' you have to check this flag to allow the System to use them during the Initial Client/Organization Setup processes. Later in this document there is a full description of how to add a [[#Chart_of_Accounts_.28CoA.29 | Chart of Accounts]] to your module.
 
* If your module has standard ''Reference Data'' you have to check this flag to allow the System to use them during the Initial Client/Organization Setup processes. Later in this document there is a full description of how to add a [[#Standard_Reference_Data | standard Reference Data]] to your module.
 
* You have also to choose the license you are using to distribute your module. Choose one ''license type'' from the drop-down list and write the ''license agreement'' that will be shown to the user when installing or updating your module. Be aware that Openbravo does not supervise the content of your module nor the license you have choosen. You are responsible to set this information properly
 
* The ''author'' of the module will be shown to the User when browsing the Central Repository and when installing. Also the User will be able to navigate from there to the module ''url''
 
* If you are working on a new version of your module you can explain what are the changes this new version includes (fixed bugs in minor versions, new features in major ones) in the "Update information" field.
 
  
The ''Include'' tab is intended only for ''Packs'' and ''Industry Templates''. In this tab you include all the modules that are members of the Pack. You can only choose from the ones that you have installed in your instance. You have to provide the ''Version Number'' for each of them following Openbravo template as described. In a later section there is a description of how the system manages [[#Version_numbers_and_how_dependencies_and_includes_are_managed | Version Numbers]] of ''Includes'' (for Packs and Industry Templates) and for ''Dependencies'' (for Modules). If you add a module here, when you package your module, this module will be packaged alongside it, in one .obx which will include both modules. This .obx file can then be used to install both modules simoultaneously. As mentioned before, this is the way to include other modules inside a "pack" of modules.
+
* Each module has its own native (base) '''language'''. In the following sections the translation process is described; by now just choose the language you prefer to develop the UI of your module. Of course, if you choose English it will be easier to disseminate (e.g., to find people to translate it to other languages).
 +
* <code>Name</code>, <code>description</code> and <code>help</code> are the properties used to explain in the repository what your module is. Write them in natural style using the native language you have chosen.
 +
* The '''Version Number''' is composed by three numbers separated by two dots to match the InfiniteERP template for version numbers. In this field, you need to have the current version you are working on (there might be multiple versions of your module).
 +
* The '''Java package''' is a unique identifier of your module and has to match the Java packaging names rules as described in the Java specification. You need to carefully set this value because you are not allowed to change it once your module is published. If your module includes Java files, they have to be packaged within your module Java package or in subpackages within it. Examples of Java packages for a module are <code>com.yourcompany.yourPackage</code>, <code>org.yourfoundation.yourPackage.yourSubpackage</code>, etc. You should name your modules with a Java package which doesn't start by <code>com.infiniteerp</code> or <code>org.openbravo</code>, but with an identifier of you, your company, or the project you belong to.
 +
* Choose the type (Module, Pack, Template) as described in the [[#Types_of_Extension_Modules|Concepts]] section.
 +
* '''In development''' is a boolean property to let the system know that you are developing on that module. Only modules '''in development''' will be exported by development tools and the System will raise an error if you try to modify some component on a module that is not in development.
 +
* Although you might have more than one module in development, you can set which one is chosen by '''default''' when developing. This is just a way to set a default value for the module when you edit the Application Dictionary.
  
The ''Dependency'' tab is intended only for Modules. In this tab you declare all the Modules that your Module depends on. It is of paramount importance that you declare them properly since the system will check that dependencies are met when the User installs or updates your module. It is also important to declare them as soon as you are aware of that because some tools and processes in the development process takes into account dependencies and the result might be wrong if they are not declared when developing your module. You declare dependencies along the modules you have installed in your instance. Typically a module will depend on User Interface Application and in turn, it has a dependency on Openbravo core and eventually in other modules. You have to provide the ''Version Number'' for each Module it depends on following Openbravo template. Optionally you can provide a second ''Version Number'' (higher than the previous) to express that your Module depends on any Version Number of that module between the two provided. Later in this document there is a complete explanation of [[#Version_numbers_and_how_dependencies_and_includes_are_managed | Version Numbers and how dependencies and includes are managed]].
+
It is recommended to restart the instance after changing the development status of a module in order to update the cache's status. Also note that production instances cannot have modules in "In development" status.
  
There is no need you to edit the ''Translation'' tab. It is a tool for translators and will be described in the [[#Translations | translation]] section.
+
* Some modules will not have UI (e.g., a connector to a banking system or a web service) so there is no need to translate them.
 +
* If your module is a '''translation module''' of another module you have to check this flag to allow users to search for translations.
 +
* If your module has a '''Chart of Accounts''', you have to check this flag to allow the System to use them during the Initial Client/Organization Setup processes.
 +
* If your module has standard '''Reference Data''' you have to check this flag to allow the System to use them during the Initial Client/Organization Setup processes.
 +
* You have also to choose the license you are using to distribute your module. Choose one '''license type''' from the drop-down list and write the '''license agreement''' that will be shown to the user when installing or updating your module.
 +
* The '''author''' of the module will be shown to the User when installing. Also the User will be able to navigate from there to the module '''URL'''.
 +
* If you are working on a new version of your module you can explain what are the changes this new version includes (fixed bugs in minor versions, new features in major ones) in the '''Update information''' field.
  
 +
The '''Include''' tab is intended only for '''Packs''' and '''Industry Templates'''. In this tab, you include all the modules that are members of the Pack. You can only choose from the ones that you have installed in your instance. You have to provide the '''Version Number''' for each of them.
  
[[Image:ModuleWindow_Packages_ob3.png]]
+
The '''Dependency''' tab is intended only for Modules. In this tab, you declare all the Modules that your Module depends on. It is of paramount importance that you declare them properly since the system will check that dependencies are met when the User installs or updates your module. It is also important to declare them as soon as you are aware of that because some tools and processes in the development process take into account dependencies and the result might be wrong if they are not declared when developing your module. Typically, a module will depend on User Interface Application and in turn, it has a dependency on InfiniteERP core and eventually on other modules.
  
 +
There is no need to edit the '''Translation''' tab. It is a tool for translators.
  
If your Module includes a table in the Application Dictionary then you need to register one (or many) '' data packages'' in your Module. For a full description on how packages are used look at the [[Data_Access_Layer| DAL developers manual]]. For each package you have to set the next properties:
+
If your Module includes a table in the Application Dictionary then you need to register one (or many) '''data packages''' in your Module. For a full description on how packages are used, visit the [[Data Access Layer|DAL developers manual]]. For each package you have to set the next properties:
* ''Name'', that will be used in the xml entities of tables assigned to it
 
* ''Description'', used to explain what your package is for
 
* ''Java package'', that has to match the Java packaging names rules as described in the Java spec. ([http://java.sun.com/docs/books/jls/third_edition/html/names.html names] and [http://java.sun.com/docs/books/jls/third_edition/html/names.html#6.8.1 package names]). It should be equal to Module package name (if there is only one package) or a subpackage of it.
 
  
If your Module includes any database schema object (a table, a stored procedure, etc.) or an AD message then you need to define the ''DB_Prefix''. This is an up to seven characters length string. All your database schema object names need to start with this prefix so it needs to match Oracle and PostgreSql naming requirements (case insensitive and stored in uppercase, alphanumeric characters and start by an alphabetic character). You can only register one DB_Prefix, just Openbravo core Module is allowed to have more than one. ''DB_Prefix'' is needed to guarantee that there are no naming clashes when installing modules.
+
* '''Name''', that will be used in the XML entities of tables assigned to it
 +
* '''Description''', used to explain what your package is for
 +
* '''Java package''', that has to match the Java packaging names rules. It should be equal to Module package name (if there is only one package) or a subpackage of it.
  
Once you have completed the set up of your Module then you need to register it in the ''Central Repository''. It is needed to ensure that your DB_Prefix and your java package are not already registered by other Modules and it is important to do it even you don't plan to publish your module. More information about this process can be found [[How_to_publish_a_Module#Register_Module|here]].
+
If your Module includes any database schema object (a table, a stored procedure, etc.) or an AD message then you need to define the <code>DB_Prefix</code>. This is a string of up to seven characters. All your database schema object names need to start with this prefix so it needs to match Oracle and PostgreSQL naming requirements (case insensitive and stored in uppercase, alphanumeric characters and start by an alphabetic character). You can only register one <code>DB_Prefix</code>; just the InfiniteERP core Module is allowed to have more than one. <code>DB_Prefix</code> is needed to guarantee that there are no naming clashes when installing modules.
  
Once you have completed the registration of your module you are ready to start developing your artifacts!
+
Once you have completed the set up of your module, it is needed to ensure that your <code>DB_Prefix</code> and your Java package are not already registered by other Modules, and it is important to do it even if you don't plan to publish your module.
  
 
=== Naming ===
 
=== Naming ===
  
It is of paramount importance to use proper names for modules. Especially for ''Java Package'' and ''DB Prefix''. This is the only way warranty there will not be conflicts when installing other modules. You can find some naming rules [[Naming_guidelines_for_modules|here]].
+
It is of paramount importance to use proper names for modules. Especially for '''Java Package''' and '''DB Prefix'''. This is the only warranty that there will not be conflicts when installing other modules.
 
 
It is a good practice to register the module in Central Repository just after setting these two properties, before starting the development. In this way they will be reserved and in case of another module having registered them, it will not be allowed requiring them to be changed.
 
  
 +
==== Java Package ====
  
==== Javapackage ====
+
'''Java Package''' should be a valid unique Java Package. These are instructions from [http://java.sun.com Java.sun.com]:
  
'''Javapackage''' should be a valid unique Java Package (see above). These are instructions from [http://java.sun.com/docs/books/jls/third_edition/html/packages.html#40169 java.sun.com]:
+
You form a unique package name by first having (or belonging to an organization that has) an Internet domain name, such as <code>sun.com</code>. You then reverse this name, component by component, to obtain, in this example, <code>com.sun</code>, and use this as a prefix for your package names, using a convention developed within your organization to further administer package names.
  
<blockquote>''You form a unique package name by first having (or belonging to an organization that has) an Internet domain name, such as sun.com. You then reverse this name, component by component, to obtain, in this example, com.sun, and use this as a prefix for your package names, using a convention developed within your organization to further administer package names.''</blockquote>
+
'''Example''':
  
For example if your company is named ''Foods & Beverages'' and you have an Internet domain called fandb.com, all your java packages should start by ''com.fandb''. If you create a CRM module its java package could be ''com.fandb.crm''.
+
If your company is named '''Foods & Beverages''' and you have an Internet domain called <code>fandb.com</code>, all your Java packages should start by <code>com.fandb</code>. If you create a CRM module, its Java package could be <code>com.fandb.crm</code>.
  
Please take into account that java packages starting by ''org.openbravo'' or ''com.openbravo'' should only be used by modules distributed by Openbravo.
+
'''Note''': Java packages starting by <code>com.infiniteerp</code> or <code>org.openbravo</code> should only be used by modules distributed by InfiniteERP.
  
 
==== DB Prefix ====
 
==== DB Prefix ====
  
It is a good practice to use a short prefix for your company followed by a prefix for your module. Following the previous example all your dbprefixes could start by ''FB'', and the one for the CRM module could be ''FBCRM''.
+
It is a good practice to use a short prefix for your company followed by a prefix for your module. Following the previous example, all your DB prefixes could start by <code>FB</code>, and the one for the CRM module could be <code>FBCRM</code>.
  
To determine if your desired DB Prefix is already in use:
+
'''About customization modules''': Usually customization modules are not intended to be published in a public repository. In this case, DBPrefix should start with <code>CUST</code>. Modules with these kinds of DBPrefixes '''cannot be registered''' in a public repository but are collision safe because no other module in a public repository can use this DBPrefix. This is an important decision to be taken before starting the module development: in case there is any chance of publishing the module at some moment, it should follow the standard rule; if it is absolutely sure that it will not be published you can use <code>CUST</code>.
  
* Access the [http://forge.openbravo.com/openbravo/moduleslist modules list] in Openbravo Forge
+
== Development of Module Artifacts ==
* Click on the Filters link at the top right of the table of modules
 
* Make sure that DB Prefix is the selected filter criterion
 
* Type your desired DB Prefix in the edit box
 
* Click the Apply button
 
  
If no module appears, then your DB Prefix has not been used, and you should register it. If another module has your desired DB Prefix, repeat the last two steps until you have created an unused one that you are happy with.
+
As stated in the Concepts section, there are four types of artifacts: '''Application Dictionary Components''', '''Software Resources''', '''Reference Data''' and '''Configuration Script'''. The requirements of your module and its technical design will define the needed artifacts to build your module.
  
 +
=== Application Dictionary Components (AD Components) ===
  
{{(!)|'''Important note about customization modules'''}}
+
Most of AD components can be included in your module but a few exceptions that are explained later in this section. The general rule to describe how Application Dictionary components are included in your module is simple: set the module field of that component to your module. If you only have one module in development or you are working in your default module it will be done automatically by the system.
  
Usually customization modules are not intended to be published in Central Repository. In this case, DBPrefix should start with '''CUST'''. Modules with these kind of DBPrefixes '''cannot be registered''' in Central Repository but are collision safe because no other module in Central Repository can use this DBPrefix. This is an important decision to be taken before starting the module development: in case there is any chance of publishing the module at some moment, it should follow the standard rule, if it is absolutely sure that it will not be published you can use ''CUST'' and do not register it.
+
An AD component will only be editable when the module it belongs to is in development, or if there is an Industry Template in development in the system. If you change a property in an AD component that is not in development the system will raise an error to avoid you to perform unintended changes.
  
== Development of Module artifacts ==
+
Translations are managed in a particular way and you don't need to care about translations when developing. But remember that your module has a native (base) language so the UI components (Windows, tabs, fields, elements, messages, textInterfaces, etc.) that you develop have to be created in that language.
  
As stated in the Concepts section there are four types of artifacts: Application Dictionary Components, Software resources, Reference Data and Configuration Script. The requirements of your module and its technical design will define the needed artifacts to build your module. This document explains the details you need to be aware for each type of artifact, one by one, related to modularity. It does not explain how to use them together to build solutions, it is described in the Openbravo Developers Guide. At the end of this document there is an explanation of a number of simple "Hello World" examples that cover all different type of solutions.
+
Access information is not included in modules, so you can forget it when developing your module.
  
=== Application Dictionary Components (AD components) ===
+
==== Table and Column ====
Most of AD components can be included in your module but a few exceptions that are explained later in this section. The general rule to describe how Applications Dictionary components are included in your module is simple: set the module field of that component to your module. If you only have one module in development or you are working in your default module it will be done automatically by the system.
 
  
An AD component will only be editable when the module it belongs to is in development, or if there is an Industry Template in development in the system. If you change a property in a AD component that is not in development the system will raise an error to avoid you to perform not intended changes.
+
Registering tables in the AD is the first exception to the general rule. Tables are not assigned directly to a module but to a data package in a module. It is needed by the DAL to properly manage packaging of generated entities and XML naming. Only packages of "in development" modules are available when you edit a table. The module of a table is the module of the package of a table.
  
Translations are managed in a particular way and you don't need to take care about translations when developing. There is a detailed description on the translation process in the [[#Translations | Translations]] section. But remember that your module has a native (base) language so the UI components (Windows, tabs, fields, elements, messages, textInterfaces, etc.) that you develop have to be created in that language.
+
Columns are assigned by default to the module of their table. But you might want to add in your module a column within a table in a different module (e.g., add a new column to the <code>M_Product</code> table in the core module). To do that you are forced to use a naming rule for that column: its physical name (<code>ColumnName</code> property) has to start by the prefix <code>EM_XXX_</code> where <code>XXX</code> is your module <code>DB_Prefix</code> (taking into account that the full column name must not be greater than 30 characters). <code>EM</code> stands for '''External Module'''. The same rule is applicable for the <code>Name</code> property which is used to generate DAL properties, therefore must be unique among different modules.
  
Access information is not included in modules so you can forget it when developing your module. In a later section it will be explained how to include a particular configuration for openbravo rbac (role based access control).
+
==== Windows, Tabs and Fields ====
 
 
 
 
[[Image:WindowWindow_ob3.png]]
 
 
 
 
 
There are some details on top of the general rule that you should understand to have better control of the content of your module. It is worth to review each type of AD component.
 
 
 
==== Table and column ====
 
Registering tables in the AD is the first exception to the general rule. Tables are not assigned directly to a module but to a data package in a module. It is needed by DAL to properly manage packaging of generated entities and xml naming. Only packages of "in development" modules are available when you edit a table. The module of a table is the module of the package of a table.
 
 
 
Columns are assigned by default to the module of their table. But you might want to add in your module a column within a table in a different module (eg. add a new column to the M_Product table in the core module). To do that you are forced to use a naming rule for that column: its physical name (''ColumnName'' property) has to start by the prefix "EM_XXX_" where "XXX" is your module DB_Prefix (taking into account that the full column name must not be greater than 30 characters). "EM" stands for ''External Module''. The ''Create Columns from DB'' process has into account all this rules when importing columns from the database. The same rule is applicable for ''Name'' property which is used to generate DAL's properties, therefore must be unique among different modules.
 
 
 
 
 
[[Image:TableWindow_ob3.png]]
 
  
==== Windows, Tabs and Fields ====
+
Windows, Tabs and Fields follow the general rule. The three of them are linked to a module. By default, when you add a tab to a window, it will be linked to the module of its window and, when you add a field to a tab, it will be linked to the module of its tab. This is true but when the window or tab modules are not in development. Then the defaulted module will be proposed.
Windows, Tabs and Fields follow the general rule. The three of them are linked to a module. By default when you add a tab to window it will be linked to the module of its window and when you add a field to a tab it will be linked to the module of its tab. This is true but when the window or tab modules are not in development. Then the defaulted module will be proposed. The ''Create fields'' process has into account all this rules when creating fields from table columns.  
 
  
When editing the field sequence the system will guarantee that you do not change the sequence number of fields that are not in you module, so if you add a new field in a tab of other module the sequence number of the original fields will not be modified. If you edit manually this information be aware that you can not modify information in a module that is not in development. It also applies if you are adding an additional tab to a window in other module.
+
When editing the field sequence the system will guarantee that you do not change the sequence number of fields that are not in your module, so if you add a new field in a tab of another module the sequence number of the original fields will not be modified.
  
The tab class and mapping is automatically managed by the system and you not need to take care about it. In a later section it is explained how Class and Mapping are managed and what you can do to add additional entries there.
+
The tab class and mapping is automatically managed by the system and you do not need to take care about it.
  
 
==== Reference ====
 
==== Reference ====
There are four types of references: Data type, List validation, Search validation and Table validation. Only List validations and Table validations can be included in a module different to Openbravo core. Data types and Search validations will be supported in modules in future releases (currently it requires to modify Openbravo WAD).
 
  
All the values included in a List validation are included in the module where the List validation is defined. You can not add in your module new values to a List validation in a different module nor modify the values included in it.
+
There are four types of references: Data type, List validation, Search validation and Table validation. Only List validations and Table validations can be included in a module different to InfiniteERP core. Data types and Search validations will be supported in modules in future releases.
  
 +
All the values included in a List validation are included in the module where the List validation is defined. You cannot add in your module new values to a List validation in a different module nor modify the values included in it.
  
[[Image:ReferenceWindow_ob3.png]]
+
==== Report and Process ====
  
==== Report and Process ====
 
 
Reports and Processes follow the general rule. You can declare a new process or report in your module by just creating a new entry in the Report and Process window and linking that entry to your module. All parameters in a Report or Process will be included in the module where the Report or Process is declared.
 
Reports and Processes follow the general rule. You can declare a new process or report in your module by just creating a new entry in the Report and Process window and linking that entry to your module. All parameters in a Report or Process will be included in the module where the Report or Process is declared.
  
For manual report and processes it is necessary to define the process mapping, this mapping can be anything within the module's package, for example ''/org.mycompany.mymodule.report/MyReport.html''.
+
For manual report and processes it is necessary to define the process mapping, this mapping can be anything within the module's package, for example <code>/org.mycompany.mymodule.report/MyReport.html</code>.
  
 
==== Form ====
 
==== Form ====
 +
 
Forms follow the general rule too. You can declare a new form in your module by just creating a new entry in the Form window and linking that entry to your module.
 
Forms follow the general rule too. You can declare a new form in your module by just creating a new entry in the Form window and linking that entry to your module.
  
 +
For forms it is necessary to define the form mapping, this mapping can be anything within the module's package, for example <code>/org.mycompany.mymodule.form/MyForm.html</code>.
 +
 +
==== Message ====
  
For forms it is necessary to define the form mapping, this mapping can be anything within the module's package, for example ''/org.mycompany.mymodule.form/MyForm.html''.
+
Messages follow the general rule but with an additional detail you need to revise. You can declare a new message in your module by just creating a new entry in the Message window and linking that entry to your module, and the search key of the message has to start by your module DB prefix (to avoid clashes between messages from different modules). It means that you cannot include in your module a message with a numeric search key to be raised by a PL/SQL object through the <code>RAISE_APPLICATION_ERROR</code> function.
  
==== Message ====
+
==== Text Interfaces ====
Messages follow the general rule but with an additional detail you need to take care. You can declare a new message in your module by just creating a new entry in the Message window and linking that entry to your module, and the search key of the message has to start by your module db prefix (to avoid clashes between messages from different modules). It means that you can not include in your module a message with a numeric search key to be raised by a pl/sql object through the RAISE_APPLICATION_ERROR function.
 
You can find more about messages in Openbravo [[Messages | here]].
 
  
==== Text interfaces ====
 
 
Text interfaces window usually is not edited manually but entries are automatically generated by the translation process when it parses files to be translated. This process takes into account the packaging of the file being translated and the text interface entry is properly assigned to the module. This process should be transparent for developers but you can browse the entries that your manual developments have created and edit them.
 
Text interfaces window usually is not edited manually but entries are automatically generated by the translation process when it parses files to be translated. This process takes into account the packaging of the file being translated and the text interface entry is properly assigned to the module. This process should be transparent for developers but you can browse the entries that your manual developments have created and edit them.
 
There is a detailed description on the translation process in the [[#Translations | Translations]] section.
 
  
 
==== Element ====
 
==== Element ====
Elements are usually automatically generated by the Synchronize terminology process when you create new columns. This process takes into account the name of the columns that you have included in your module and searchs in your module and the modules your module depends on for an element with that column name. If it is found your column will be linked to that element, if not a new element will be created in your module. This process should be transparent for developers but you can browse the elements included in your module and edit them.
 
  
==== Field category, Auxiliar input, Callouts and Validations ====
+
Elements are usually automatically generated by the Synchronize terminology process when you create new columns. This process takes into account the name of the columns that you have included in your module and searches in your module and the modules your module depends on for an element with that column name. If it is found, your column will be linked to that element; if not, a new element will be created in your module. This process should be transparent for developers but you can browse the elements included in your module and edit them.
These four Application Dictionary components follow the general rule too. You can declare a new component of them in your module by just creating a new entry in the proper window and linking that entry to your module.
 
  
Auxiliar input name must start with the module's DBPrefix.
+
==== Field Category, Auxiliary Input, Callouts and Validations ====
  
==== Model - Implementation mapping ====
+
These four Application Dictionary components follow the general rule too. You can declare a new component of them in your module by just creating a new entry in the proper window and linking that entry to your module.
Model - Implementation mapping is generalization of the Model-Object concept that was present in previous releases. You can see a detailed description in the explanation of the [[#Model_-_Implementation_concept | Model - Implementation concept]].
 
  
Through this new window you can include in your module the entries you need to add to the web.xml file of Openbravo context.
+
Auxiliary input name must start with the module's DBPrefix.
  
 +
==== Model - Implementation Mapping ====
  
[[Image:ModelImplementationWindow_ob3.png]]
+
Model - Implementation mapping is a generalization of the Model-Object concept that was present in previous releases. Through this new window you can include in your module the entries you need to add to the <code>web.xml</code> file of the InfiniteERP context.
  
 
Model - Implementation mappings follow the general rule. You can declare a new entry in your module by just creating a new record in the Model - Implementation mapping window and linking that entry to your module. All mappings and parameters assigned to it will be included in the module where the Model - Implementation mapping is declared.
 
Model - Implementation mappings follow the general rule. You can declare a new entry in your module by just creating a new record in the Model - Implementation mapping window and linking that entry to your module. All mappings and parameters assigned to it will be included in the module where the Model - Implementation mapping is declared.
  
 
=== Software Resources ===
 
=== Software Resources ===
To develop your module you may require to include some software resources. Software resources are Openbravo ERP components not expressed as metadata such as xml definition of database schema object, java classes, jar libraries, XML files, etc. All you need to add to your module has to be packaged within openbravoMainFolder/modules/yourModuleJavaName (eg. for the module org.openbravo.examples.helloworld the packaging is ''/home/user/src/openbravo/modules/org.openbravo.examples.helloworld'' in a linux box or ''c:\openbravo\modules\org.openbravo.examples.helloworld'' in a windows one). Within this folder you have the standard openbravo folders to hold your software resources (src, src-db, lib, etc). See the image in the [[#Packaging_and_.obx_files | packaging section]] for details.
 
  
The build process of Openbravo takes into account the source code structure that is split into modules. Be aware that this concept is completely different from the srcClient that Openbravo used in previous releases: you are not allowed to physically overwrite a file in Openbravo core distribution. In fact, the packaging of your software resources should be located in com.yourCompany.xxx or org.yourCompany.xxx so you will not use org.openbravo.xxx to package your code any more.
+
To develop your module you may require to include some software resources. Software resources are InfiniteERP components not expressed as metadata such as XML definition of database schema objects, Java classes, JAR libraries, XML files, etc. All you need to add to your module has to be packaged within <code>InfiniteERPMainFolder/modules/yourModuleJavaName</code>. Within this folder, you have the standard InfiniteERP folders to hold your software resources (<code>src</code>, <code>src-db</code>, <code>lib</code>, etc).
  
Similarly to AD components, although this general rule for packaging is applied to all software resources there are some details for each type of software resource (Database schema objects, java classes, jar libraries, web static content, etc.) that you need to be aware when developing your module.
+
The build process of InfiniteERP takes into account the source code structure that is split into modules. Be aware that this concept is completely different from the <code>srcClient</code> that was used in previous releases: you are not allowed to physically overwrite a file in the InfiniteERP core distribution. In fact, the packaging of your software resources should be located in <code>com.yourCompany.xxx</code> or <code>org.yourCompany.xxx</code> so you will not use <code>com.infiniteerp.xxx</code> to package your code any more.
  
==== Database schema objects ====
+
Similarly to AD components, although this general rule for packaging is applied to all software resources there are some details for each type of software resource (Database schema objects, Java classes, JAR libraries, web static content, etc.) that you need to be aware when developing your module.
The typical flow to add a new database schema object (table, column, constraint, index, trigger, view, stored procedure, function) or modify it in Openbravo ERP is as it follows:
 
* a developer uses her/his preferred tool as database client for development in Oracle or PostgreSql
 
* using sql scripts or GUI tools she/he creates or modifies the database schema object in the database following Openbravo standards.
 
* if the database schema object is mapped with any Application dictionary (Tables&Columns, Reports&Processes) then the developer import the new db schema object from the database to the Application Dictionary. This process adds some new lines in AD tables. After that the developer usually adjusts the imported information -eg. running the synchronize terminology process- and complete AD information to fully describe the solution she/he targets. It might require as well to create some Openbravo code (java files, xsql files, etc.) to complete the solution
 
* once the solution is fully described the developer builds the system to test that it is working as desired
 
* the last process is to export the database to xml files through DBSourceManager. This tool export every database schema object to a xml file that uses a common syntax for both Oracle and PostgreSql so you can have different development environments commiting to the same line of code. Application Dictionary data is also exported in this process. So there are two different types of xml files exported by DBSourceManager: model (db schema objects) and sourcedata (Application Dictionary metadata).
 
  
From a modularity perspective there is no need you to do any additional task to take care of Application Dictionary metadata since it is managed by the system as described in the previous [[#Application_Dictionary_Components_.28AD_components.29 | Application Dictionary Components]] section. But to avoid naming clashes in the database and to allow DBSourceManager to know the module of not mapped database schema objects it is required to follow the next naming rule for database schema objects:
+
==== Database Schema Objects ====
* All main objects (tables, triggers, views, functions, stored procedures) have to start by your module db_prefix followed by an underscore ("_") symbol (eg. MYMOD_MYTABLE, MYMOD_MYPROCEDURE, etc.).
 
* Every object (tables, constraints, indexes, functions, triggers) needs to have a unique name in the database. To avoid any kind of duplication, constraint and index names in particular need to start with their table name. This ensures that there will be no name duplication in the whole database.
 
* Subparts of main objects (columns, constraints, indexes) are supposed to belong to the module of the main part except if their name starts by "EM_" + db_prefix + "_" (eg. EM_MYMOD_MYCOLUMN, EM_MYMOD_MYCONSTRAINT, etc.). EM stands for External Module. So you can use standard column names in your tables (eg. C_BPARTNER_ID, M_PRODUCT_ID, NAME, etc.) but if you want to add in your module a "part" (column, constraint, index) to a table in another module you need to use the prefix "EM_" + db_prefix + "_" for the name of that part. In any case, constraints and indexes in the same module and their table must start with the module's db_prefix, this is in this way because their name must be unique in the whole database.
 
  
And that's all. Following this simple rule you can include in your module as many database schema objects as you want. But be aware that you can not modify database schema objects in other modules as it would break the main rule: "a module can not modify components in other modules".
+
The typical flow to add a new database schema object (table, column, constraint, index, trigger, view, stored procedure, function) or modify it in InfiniteERP is as follows:
  
When DBSourceManager exports the database it will only take into account modules "in development", the other ones will not be exported. The exported xml files will be located within the src-db/database folder within the module folder. Look at [[#Packaging_and_.obx_files | packaging]] to see an example.
+
* A developer uses her/his preferred tool as database client for development in Oracle or PostgreSQL
 +
* Using SQL scripts or GUI tools she/he creates or modifies the database schema object in the database following InfiniteERP standards
 +
* If the database schema object is mapped with any Application Dictionary (Tables & Columns, Reports & Processes) then the developer imports the new DB schema object from the database to the Application Dictionary. This process adds some new lines in AD tables. After that, the developer usually adjusts the imported information — e.g., running the synchronize terminology process — and completes AD information to fully describe the solution she/he targets. It might require as well to create some InfiniteERP code (Java files, XSQL files, etc.) to complete the solution
 +
* Once the solution is fully described, the developer builds the system to test that it is working as desired
 +
* The last process is to export the database to <code>.xml</code> files through '''DBSourceManager'''. This tool exports every database schema object to a <code>.xml</code> file that uses a common syntax for both Oracle and PostgreSQL so you can have different development environments committing to the same line of code. Application Dictionary data is also exported in this process. So there are two different types of <code>.xml</code> files exported by '''DBSourceManager''': ''model'' (DB schema objects) and ''sourcedata'' (Application Dictionary metadata)
  
At the end of this document there are some examples explained that show how to include in your module any type of database schema object. You can use them as a reference to develop your module.
+
From a modularity perspective, there is no need to do any additional task to take care of Application Dictionary metadata since it is managed by the system as described in the previous [[#Application_Dictionary_Components_(AD_Components)|Application Dictionary Components]] section. But to avoid naming clashes in the database and to allow '''DBSourceManager''' to know the module of not-mapped database schema objects it is required to follow the next naming rule for database schema objects:
  
===== Exceptions =====
+
* All main objects (tables, triggers, views, functions, stored procedures) have to start by your module DB prefix followed by an underscore ("_") symbol (e.g., <code>MYMOD_MYTABLE</code>, <code>MYMOD_MYPROCEDURE</code>, etc.)
 +
* Every object (tables, constraints, indexes, functions, triggers) needs to have a unique name in the database. To avoid any kind of duplication, constraint and index names in particular need to start with their table name. This ensures that there will be no name duplication in the whole database
 +
* Subparts of main objects (columns, constraints, indexes) are supposed to belong to the module of the main part except if their name starts by "EM_" + DB prefix + "_" (e.g., <code>EM_MYMOD_MYCOLUMN</code>, <code>EM_MYMOD_MYCONSTRAINT</code>, etc.). EM stands for External Module. So you can use standard column names in your tables (e.g., <code>C_BPARTNER_ID</code>, <code>M_PRODUCT_ID</code>, <code>NAME</code>, etc.) but if you want to add in your module a "part" (column, constraint, index) to a table in another module you need to use the prefix "EM_" + DB prefix + "_" for the name of that part
  
It is possible to define database schema objects within a module that do not follow the naming rules explained in the section above. This is specially useful in order to move to modules existent Openbravo ERP instances in older versions. It is important to note that '''this feature should not be used for new developments in general'''. If a module contains a naming exception, it will not be possible to publish it to the Central Repository, because it would not be possible to guarantee that the object defined as a naming exception would not collide with another object defined in a different module.
+
Following this simple rule, you can include in your module as many database schema objects as you want. But be aware that you cannot modify database schema objects in other modules as it would break the main rule: "a module cannot modify components in other modules."
  
When a database schema object is defined as an exception for a module it is exported to that module instead to the one that should be according to its name and the naming rules.
+
When '''DBSourceManager''' exports the database, it will only take into account modules "in development"; the other ones will not be exported. The exported XML files will be located within the <code>src-db/database</code> folder within the module folder.
  
Exceptions are defined in '''Application Dictionary || Module  ||  Module  >>  Naming Exceptions''' tab which contains two fields:
+
'''Naming Exceptions''': It is possible to define database schema objects within a module that do not follow the naming rules explained above. This is specially useful in order to move to modules existent InfiniteERP instances in older versions. It is important to note that '''this feature should not be used for new developments in general'''. If a module contains a naming exception, it will not be possible to publish it to a public repository, because it would not be possible to guarantee that the object defined as a naming exception would not collide with another object defined in a different module.
*'''DB Object Type''': Defines the database object type (table, function, index...)
 
*'''Object name''': It is the database object name. Note that it is the name in database, not in Application Dictionary.
 
  
===== Extension Points =====
+
When a database schema object is defined as an exception for a module it is exported to that module instead of to the one that should be according to its name and the naming rules.
Extension Points allow the developer to attach execution code to predefined specific points inside Openbravo PL/SQL functions. This functionality can be used to extend the functionality of some Core functions, without overwriting them in any way. This way of extending the functionality fits very well with Modularity, as it allows extension but also keeps maintainability and upgradeability.
 
  
More about Extension Points can be found [[ExtensionPoints|here]]  and [[How_to_use_an_Extension_Point|here]].
+
Exceptions are defined in <code>Application Dictionary > Module > Module > Naming Exceptions</code> tab which contains two fields:
  
==== Java classes, other Openbravo MVC objects and jar libraries ====
+
* '''DB Object Type''': Defines the database object type (table, function, index...)
Java classes, other Openbravo MVC objects (html, xml and xsql files) and jar libraries follow the general rule to add software resources in your module. You have to package this code within the src folder located in your module folder.
+
* '''Object name''': It is the database object name. Note that it is the name in the database, not in Application Dictionary
 
  
[[Image:ResourcePackaging.png]]
+
'''Extension Points''': Extension Points allow the developer to attach execution code to predefined specific points inside InfiniteERP PL/SQL functions. This functionality can be used to extend the functionality of some Core functions, without overwriting them in any way. This way of extending the functionality fits very well with Modularity, as it allows extension but also keeps maintainability and upgradeability.
  
 +
==== Java Classes, Other InfiniteERP MVC Objects and JAR Libraries ====
  
When Openbravo ERP builds the system it will dynamically add to its java project all the src folders within all installed modules as java resources of the project. It uses an intermediate location, build folder, to generate code from xsql files and to compile all java resources and put them together. You can include in your module jar libraries made by you or by any other third party and use them along your code. All jar libraries included in the lib\runtime folder inside your module, are added to the classpath at compilation time and finally deployed to the openbravo context.  
+
Java classes, other InfiniteERP MVC objects (HTML, XML and XSQL files) and JAR libraries follow the general rule to add software resources in your module. You have to package this code within the <code>src</code> folder located in your module folder.
  
When working with Eclipse, if modules are added manually to the workspace (ie. not through the Module Management Console), the module src/ folder needs to be added to the build path manually.
+
When InfiniteERP builds the system it will dynamically add to its Java project all the <code>src</code> folders within all installed modules as Java resources of the project. It uses an intermediate location, build folder, to generate code from XSQL files and to compile all Java resources and put them together. You can include in your module JAR libraries made by you or by any other third party and use them along your code. All JAR libraries included in the <code>lib/runtime</code> folder inside your module, are added to the classpath at compilation time and finally deployed to the InfiniteERP context.
  
After the generation of code and compile process the build process deploys all the content to the openbravo context in the servlet container. There are two modes of deployment -class and war- that are explained later in the Advanced Concepts section.
+
After the generation of code and compile process the build process deploys all the content to the InfiniteERP context in the servlet container. There are two modes of deployment — ''class'' and ''war'' — that are explained in [[Development Build Tasks]].
  
==== Web Static content (css files, images, javaScript) ====
+
==== Web Static Content (CSS files, images, JavaScript) ====
If you need to add some web Static content (css, images and javaScript) to your module you have to place these resources in the ''web'' folder of your module, within a folder named as the java package of your module to avoid clashes of files when deploying resources from different modules.
 
  
When the system is built all files in the ''web'' folder of your module are copied to ''WebContent'' and from there it is deployed to openbravo context in a standard way so this resources can be accessed from the pages in your module by referencing them. Take into account that xmlEngine performs an automatic translation of urls through a replace of "../../../../../web" (replaceWhat parameter) by "@actual_url_context@/web" (replacWith parameter), being "@actual_url_context@" the absolute path to your openbravo context (eg. ''http://localhost:8880/openbravo'').
+
If you need to add some web static content (CSS, images and JavaScript) to your module you have to place these resources in the <code>web</code> folder of your module, within a folder named as the Java package of your module to avoid clashes of files when deploying resources from different modules.
  
The Solitaire module is designed to demonstrate how to include typical web static content in your module. Through this example it is simple to understand how it works. For example, this is a snippet of Solitaire.html to reference to solitaire.js file that is located within the ''web/org.openbravo.examples.solitaire'' folder of Solitaire module:
+
When the system is built all files in the <code>web</code> folder of your module are copied to <code>WebContent</code> and from there it is deployed to the InfiniteERP context in a standard way so these resources can be accessed from the pages in your module by referencing them.
  
<script language="JavaScript" src="../../../../../web/org.openbravo.examples.solitaire/solitaire.js" type="text/javascript"></script>
+
You can also reference other web static content resources included in core or other modules. In that case, remember to explicitly declare the dependency to that module.
  
At execution time, once openbravo context is deployed and loaded you can get solitaire.js javascript library from @actual_url_context@/web/org.openbravo.examples.solitaire/solitaire.js. When the main page of Solitaire module is delivered, xmlEngine will replace "../../../../../web" by "@actual_url_context@/web" and by so properly referencing to the available resource.
+
==== Config Files ====
  
Of course you can also reference to other web static content resources included in core or other modules. In that case remember to explicitily declare the dependency to that module.
+
You might also need to include some configuration files in the <code>config</code> folder of your module. These files will be copied to <code>WebContent/WEB-INF</code> when the system is built and deployed to the InfiniteERP context.
  
==== Config files ====
+
To avoid clashing of files deployed by different modules, files within the config folder should be prefixed with the PackageName of the module.
You might also need to include some configuration files in the ''config'' folder of your module. These files will be copied to WebContent/WEB-INF when the system is built and deployed to openbravo context.
 
  
For example, in HelloWorldService module there is file named ''org.openbravo.examples.webservice-provider-config.xml'' within the ''config'' folder. This file is copied to openbravo context and by this mean the class that implements the webservice is declared.
+
=== Reference Data ===
 
 
To avoid clashing of files deployed by different modules files within config-folder should be prefixed with the PackageName of the module.
 
  
=== Reference Data ===
+
InfiniteERP Modularity supports Reference Data: business information referred by transactions and that tend not to change frequently such as translations, charts of accounts, tax codes, banks, product categories, etc. They can be defined at system, client or organization level and it will define when they are loaded into the instance: System information will be loaded at installation time while Client and Organization information will be loaded during the '''Initial Client/Organization Setup''' or '''Enterprise Module Management''' processes.
Openbravo Modularity supports Reference Data: business information referred by transactions and that tend not to change frequently such as translations, charts of accounts, tax codes, banks, product categories, etc. They can be defined at system, client or organization level and it will define when they are loaded into the instance: System information will be loaded at intallation time while Client and Organization information will be loaded during the "Initial Client/Organization Setup" or "Enterprise module management" processes.
 
  
Reference data modules are also versioned and can publish updates and upgrades during their life cycle.  
+
Reference data modules are also versioned and can publish updates and upgrades during their life cycle.
  
There are three types of reference data supported: Translations, Chart of Accounts and standard Reference Data.
+
There are three types of reference data supported: Translations, Chart of Accounts and Standard Reference Data.
  
 
==== Translations ====
 
==== Translations ====
Translation modules are a special kind of module. They have to be marked as "Is translation module" in the Module window. No other contents than translations are allowed in translation modules, and only translations for one module to only one language, the native language declared for the module (eg. translation for core module to Spanish, translation for HR module to French) . Translation modules only depend on the module they translate.
 
  
Create a translation module is a straightforward process. First you have to create your module as usual. Remember to define it as "translation module" and define the its native language as the language you are going to translate to, and to use the native language of the module writing its name, description, etc. Keep unchecked the other properties related to reference data (''Translation required'', ''Has chart of accounts'' and ''Has reference data''). This module does not need any Includes, Data packages and DB prefix and will only depend on the module version you are translating.  
+
Translation modules are a special kind of module. They have to be marked as "Is translation module" in the Module window. No other contents than translations are allowed in translation modules, and only translations for one module to only one language — the native language declared for the module (e.g., translation for core module to Spanish, translation for HR module to French). Translation modules only depend on the module they translate.
  
Then create the main folder of your module -named as its javapackage- within ''modules'' folder, you can do it manually or just by executing ''export.database'' Ant task (remember that the module has to be ''In development'').  
+
Create a translation module is a straightforward process. First you have to create your module as usual. Remember to define it as "translation module" and define its native language as the language you are going to translate to. Keep unchecked the other properties related to reference data (<code>Translation required</code>, <code>Has chart of accounts</code> and <code>Has reference data</code>). This module does not need any Includes, Data packages and DB prefix and will only depend on the module version you are translating.
  
Then all you have to do is install the module you plan to translate and declare the dependency of your translation module to this module, and follow the standard translation process following [[Localization_Process#Creating_a_translation_module | this document]]. The export languages process splits the xml files in different folders for each module installed: core is exported directly to the language folder (eg. es_ES) and any other installed module will be exported to a folder named with module package name within the language folder (eg. es_ES/org.openbravo.examples.helloworld). Once you have completed the translation you have to copy the translated xml files of the translated module -only these ones- to referencedata/translation folder within your module folder, and package it as usual by executing the ant task ''package.module -Dmodule="yourModuleJavaPackage"'' that will create an .obx file that is ready to be published or distributed.
+
Then create the main folder of your module — named as its Java package — within the <code>modules</code> folder. Then all you have to do is install the module you plan to translate and declare the dependency of your translation module to this module, and follow the standard translation process. Once you have completed the translation you have to copy the translated XML files of the translated module only these ones to <code>referencedata/translation</code> folder within your module folder, and package it as usual.
  
Translation information is always at System level. When a translation module is installed the process takes care of all details to import a transalation pack: it will mark the Language as System Language if it was not and will load all translations in Openbravo Application Dictionary.
+
Translation information is always at System level. When a translation module is installed the process takes care of all details to import a translation pack: it will mark the Language as System Language if it was not and will load all translations in the InfiniteERP Application Dictionary.
  
 
==== Chart of Accounts (CoA) ====
 
==== Chart of Accounts (CoA) ====
Tipically you should add just one Chart of Account in your module, although you can create as many modules including CoA as you want and then put them together in a pack if needed. Chart of Accounts are stored in a particular .csv file, please read [http://wiki.openbravo.com/wiki/Creating_Accounts_Files this explanation] to learn more about how to create a .csv file for a Chart of Accounts and test it is ok.
 
  
It is easy to create a module including a Chart of Accounts once you have prepared the .csv file. All you need to do is create a new module and mark as checked the ''Has a chart of Accounts'' property. Keep unchecked the other properties related to reference data (''Translation required'', ''Is translation module'' and  ''Has reference data''). This module does not need any Includes, Data packages and DB prefix and will only depend on the core version you are using (the structure of the .csv file is defined in core).  
+
Typically you should add just one Chart of Accounts in your module, although you can create as many modules including CoA as you want and then put them together in a pack if needed. Chart of Accounts are stored in a particular <code>.csv</code> file.
 +
 
 +
It is easy to create a module including a Chart of Accounts once you have prepared the <code>.csv</code> file. All you need to do is create a new module and mark as checked the <code>Has a chart of Accounts</code> property. Keep unchecked the other properties related to reference data. This module does not need any Includes, Data packages and DB prefix and will only depend on the core version you are using (the structure of the <code>.csv</code> file is defined in core).
 +
 
 +
Then create the main folder of your module — named as its Java package — within the <code>modules</code> folder. Within the main folder you have to create the subfolder <code>referencedata</code> (all in lower case) and within it the folder <code>accounts</code> and place your <code>.csv</code> file there. Remember that folders are case sensitive.
  
Then create the main folder of your module -named as its javapackage- within ''modules'' folder, you can do it manually or just by executing ''export.database -Dmodule=yourModuleJavaPackage'' ant task (remember that the module has to be ''In development''). Withing the main folder you have to create the subfolder ''referencedata'' (all in lower case) and within it the folder ''accounts'' and place your .csv file there. Remember that folders are case sensitive so the folder must be identically named and use the correct capitalization.  
+
Now your module is ready to be packaged. Execute the Ant task <code>package.module -Dmodule="yourModuleJavaPackage"</code> and it will create an <code>.obx</code> file that is ready to be published or distributed.
  
Now your module is ready to be packaged. Execute the ant task ''package.module -Dmodule="yourModuleJavaPackage"'' and it will create an .obx file that is ready to be published or distributed.
+
Chart of Accounts are always at Client/Organization level so nothing happens when you install this type of modules but just that the chart of accounts is available to be applied to new clients (during Initial Organization Setup), new organizations (during Initial Organization Setup) or to existing Client/Organizations (by Enterprise Module Management).
  
Chart of Accounts are always at Client/Organization level so nothing happens when you install this type of modules but just that the chart of accounts is available to be applied to new clients (during Initial Organization Setup), new organizations (during Initial Organization Setup) or to existing Client/Organizations (by Enterprise Module management).
+
==== Standard Reference Data ====
  
====Standard Reference Data====
+
You can also include any other data in your module through standard reference data using data sets.
You can also include any other data in your module through standard reference data using data sets.  
 
  
 
First you need to create in your instance the data you want to include. It could be taxes for a particular country, product categories or a collection of alerts for a particular industry or any other data. You can combine different data from different tables in your module.
 
First you need to create in your instance the data you want to include. It could be taxes for a particular country, product categories or a collection of alerts for a particular industry or any other data. You can combine different data from different tables in your module.
  
After that, the next step is to create a module and mark as checked the ''Has reference data'' property. Keep unchecked the other properties related to reference data (''Translation required'', ''Is translation module'' and ''Has chart of accounts''). Complete the ''Reference data description'' with information about the data you are including (this description might be different from the module descriptions since the module might include some other content). This module does not need any Includes, Data packages and DB prefix and will depend on the module versions that define the data structure you aim to include (eg. if your data comes from table defined in core 2.50.1234 then it will only depend on this module-version).
+
After that, the next step is to create a module and mark as checked the <code>Has reference data</code> property. Keep unchecked the other properties related to reference data. Complete the '''Reference data description''' with information about the data you are including. This module does not need any Includes, Data packages and DB prefix and will depend on the module versions that define the data structure you aim to include.
  
Then you have to create within your module as many data sets as you need to define your data. A data set is a collection of data defined by the tables where those data are stored, the rows included -defined through a filter clause for each table- and the columns you want to include for each table. Data sets support advanced data definition to include full business objects (eg. when including an invoice you might ask the system to include all its members -lines, taxes, etc.- as well). Click [[Datasets | here]] for a general description of datasets.
+
Then you have to create within your module as many data sets as you need to define your data. A data set is a collection of data defined by the tables where those data are stored, the rows included defined through a filter clause for each table and the columns you want to include for each table.
  
You can create datasets in the ''Data Set'' Window within the Application Dictionary menu folder.  
+
You can create data sets in the '''Data Set''' window within the Application Dictionary menu folder.
  
[[Image:DataSetWindow_ob3.png]]
+
There are some details you need to be aware when creating data sets:
  
There are some details you need to be aware when creating data sets:
+
* The data set should be assigned to your module in which you will distribute those data
* Of course the data set should be assigned to your module in which you will distribute those data
+
* Data access level defines the level at which data will be imported and when:
* Data access level is related to data access level in AD tables, read [http://wiki.openbravo.com/wiki/Functional_Documentation/General_Setup#Data_access_level here] for more details. It defines the level at those data will be imported -of course it will be restricted to the levels allowed by the table where data is stored- and when data is imported in the instance that installs the module:
+
  * '''System only''': imported at System level at installation time. Only tables with <code>System only</code>, <code>System/client</code> and <code>All</code> data access level are allowed
** '''System only''': it will be imported at System level at installation time. Only tables with ''System only'', ''System/client'' and ''All'' data access level are allowed in ''System only'' data sets (eg. Roles, Alert rules, etc.)
+
  * '''System/client''': imported at Client level during "Initial Client Setup" or "Enterprise module management" processes. Only tables with <code>System/client</code>, <code>Client/Organization</code> and <code>All</code> data access level are allowed
** '''System/client''': it will be imported at Client level during "Initial Client Setup" or "Enterprise module management" processes. Only tables with ''System/client'', ''Client/Organization'' and ''All'' data access level are allowed in ''System/client'' data sets (eg. Roles, Product categories, etc.)
+
  * '''Client/organization''': imported at Client or Organization level during '''Initial Client Setup''', '''Initial Organization Setup''' or '''Enterprise module management''' processes
** '''Client/organization''': it will be imported at Client or Organization level during "Initial Client Setup", "Initial Organization Setup" or "Enterprise module management" processes. Only tables with ''Client/Organization'' and ''Organization'' data access level are allowed in ''Client/Organization'' data sets (eg. Product categories, Business partners, etc.)
+
  * '''Organization''': imported at Organization level during "Initial Organization Setup" or "Enterprise module management" processes
** '''Organization''': it will be imported at Organization level during "Initial Organization Setup" or "Enterprise module management" processes. Only tables with ''Client/Organization'', ''Organization'' and ''All'' data access level are allowed in ''Organization'' data sets (eg. Business partners, Sales orders, etc.)
+
* Check the '''Export allowed''' field to show the '''Export Reference Data''' button. With this button, you will be able to export your data to XML files and this way include them in your <code>.obx</code> file
* Check the ''Export allowed'' field to show the ''Export Reference Data'' button. From this button you will be able to export your data to xml files and this way include them in your .obx file
 
  
 
Next step is to define the collection of tables included in your data set.
 
Next step is to define the collection of tables included in your data set.
 
[[Image:DataSetTableWindow_ob3.png]]
 
  
 
Again some details you need to be aware:
 
Again some details you need to be aware:
  
 
* You can add as many tables as you need in your data set
 
* You can add as many tables as you need in your data set
* For each table you can add a ''SQL where clause'' to filter data in the table. In the example above it is filtering by Product categories in a particular client. Click [[Dataset#DatasetTable_where_clause|here]] for more information on the DatasetTable where clauses.
+
* For each table you can add a <code>SQL where clause</code> to filter data in the table
 
* You can include all columns in the table or declare one by one the ones you want to include
 
* You can include all columns in the table or declare one by one the ones you want to include
* Tipically you will not want to include audit info in your data, you can exclude audit info columns
+
* Typically you will not want to include audit info in your data, you can exclude audit info columns
* By default your data set includes just the records in the data set tables matching the SQL where clause criteria. But you can define the table in your data set as "Is business object". If you do it then the system will export not only the records in the table matching you SQL where clause but recursively any other record in the system that has a foreing key to these records and that is defined as member of the referenced record (business object) through the [[Database_Model/org.openbravo.model.ad.datamodel/AD_Column#Link_to_Parent_Column | "Is parent"]] attribute in AD column.
+
* By default your data set includes just the records in the data set tables matching the SQL where clause criteria. But you can define the table in your data set as '''Is business object'''. If you do it then the system will export not only the records in the table matching your SQL where clause but recursively any other record in the system that has a foreign key to these records
 
 
Take into account that the system will export not only the data defined by you data set but also any information referenced by it. This way it is guaranteed that the system will be able to import that data in any other instance although the referenced data does not exist there. If it is the case the import process will also import any referenced data needed to complete the operation.
 
  
 
Now you have to define the columns included for each table.
 
Now you have to define the columns included for each table.
  
[[Image:DataSetColumnWindow_ob3.png]]
+
Usually there is no need to define columns in your table since typically you want to include all of them but audit info. Sometimes you might want to exclude some other columns by checking the '''Excluded''' field.
  
Usually there is no need to define columns in your table since tipically you want to include all of them but audit info and you can do it in the table itself as described before. Some times you might want to exclude some other columns by checking the ''Excluded'' field.
+
Once you have completed the definition of all your data sets you have to export them to XML files so they are included in your <code>.obx</code> file when packaging your module. To do that you have to click on the '''Export Reference Data''' button in the data set header. It will create an XML file named as the data set in <code>referencedata/standard</code> subfolder within your module folder. Finally package it as usual by executing the Ant task <code>package.module -Dmodule="yourModuleJavaPackage"</code> that will create an <code>.obx</code> file that is ready to be published or distributed.
  
Once you have completed the definition of all your data sets you have to export them to xml files so they are included in your .obx file when packaging your module. To do that you have to click on the ''Export Reference Data'' button in the data set header. It will create a xml file named as the data set in referencedata/standard subfolder within your module folder. Of course you can run this process as many times as you need to fine tune your data. Finally package it as usual by executing the ant task ''package.module -Dmodule="yourModuleJavaPackage"'' that will create an .obx file that is ready to be published or distributed.  
+
As described before you can also publish new versions of your reference data modules. Take into account that to ensure data consistency reference data is not deleted from the instance when applying an update/upgrade where the new data set does not include some records originally included. So instead of remove them from the data set you should inactivate them.
  
As described before you can also publish new versions of your reference data modules. Take into account that to ensure data consistency reference data is not deleted from the instance when applying an update/upgrade where the new data set does not include some records originally included. So instead of remove them from the data set you should inactivate them.
+
==== Advanced Topics ====
  
==== Advanced topics ====
 
 
There are special cases that must be taken into account when including tables and columns to reference data.
 
There are special cases that must be taken into account when including tables and columns to reference data.
===== All columns in dataset are always reset, when updating reference data =====
 
In case you are developing a module that contains a dataset at a ''System/client'', ''Client/Organization'' or ''Organization'' data access level (actually all the possible ones, in except of ''System only''), you must take into account that every time the user updates the reference data application (through Enterprise Module Management window) all the included columns will be updated. This is useful, but also little bit dangerous:
 
 
Imagine that you need to add records belonging to AD_Sequence table in a dataset, and you include all columns of the table in the dataset.
 
  
The sequences are used, for example, by the documents. Every document has got a sequence associated to it. Every time a new invoice is created and saved, the sequence provides a new number (stored in the ''CurrentNext'' column), and increments its value for the next time a new number is requested.
+
'''All columns in dataset are always reset, when updating reference data''': In case you are developing a module that contains a dataset at a '''System/client''', '''Client/Organization''' or '''Organization''' data access level, you must take into account that every time the user updates the reference data application (through '''Enterprise Module Management''' window) all the included columns will be updated. This is useful, but also a little bit dangerous.
 
 
The user applies the dataset, and everything goes fine: sequences are imported to database (with let's say, ''CurrentNext''='1000000'). User starts to use the sequence, so ''CurrentNext'' value is incremented (let's say that now ''CurrentNext''='1000123'). Now a new version of the dataset is published because, for example, some more sequences are included to it. User updates the module, and updates dataset in Enterprise Module Management window. In that action, the ''CurrentNext'' value of the original sequence is reset from '100123' to '1000000' again.
 
  
 
What can be done in order to avoid this kind of issues? Just don't include that value in the dataset, and set it through the default value of the column.
 
What can be done in order to avoid this kind of issues? Just don't include that value in the dataset, and set it through the default value of the column.
  
 
=== Module Scripts and Build Validations ===
 
=== Module Scripts and Build Validations ===
It is possible that your module needs to check if the system complies with some specific rule before installing it. If this is the case, a Build Validation can be used to verify it. A Build Validation is basically a process, defined as a Java class, which can connect to the database and to the Openbravo sources, check whatever the developer wants, and finally return a result of the validation. If the result is not positive, the module is not applied in the system.
 
  
Also, it is possible that your module needs to do specific transformations to the system while installing. This changes can be of basically any kind, such as modifying some data in the system, or adding some database object which uses some Oracle or PostgreSQL specific syntax which makes it not possible to add it through our standard dbsourcemanager+xml files. For this, you can use Module Scripts, which like Build Validations, are defined as a Java class which can connect to the database, and do any kind of modifications to client data.
+
It is possible that your module needs to check if the system complies with some specific rule before installing it. If this is the case, a Build Validation can be used to verify it. A Build Validation is basically a process, defined as a Java class, which can connect to the database and to the InfiniteERP sources, check whatever the developer wants, and finally return a result of the validation. If the result is not positive, the module is not applied in the system.
 +
 
 +
Also, it is possible that your module needs to do specific transformations to the system while installing. This changes can be of basically any kind, such as modifying some data in the system, or adding some database object which uses some Oracle or PostgreSQL specific syntax which makes it not possible to add it through the standard DBSourceManager + XML files. For this, you can use Module Scripts, which like Build Validations, are defined as a Java class which can connect to the database, and do any kind of modifications to client data.
  
If you want to know more about how to create Build Validations and Module Scripts, you can check [[How_to_create_build_validations_and_module_scripts|this link]]. If you plan to use a module script to create a database object which uses some kind of database specific syntax or feature, you should exclude it from the dbsourcemanager standard model. To learn how to do this, read [[How_to_exclude_Database_Physical_Objects_From_Model|this document]]
+
If you want to know more about how to create Build Validations and Module Scripts, you can check [[How to create build validations and module scripts|How to Create Build Validations and Module Scripts]]. If you plan to use a module script to create a database object which uses some kind of database specific syntax or feature, you should exclude it from the DBSourceManager standard model. To learn how to do this, read [[How to exclude Database Physical Objects From Model|How to Exclude Database Physical Objects From Model]].
  
 
=== Configuration Script ===
 
=== Configuration Script ===
  
Up to know we have seen how to extend Openbravo through modules. As you remember modules are able to add new artifacts -application dictionary components, software resources and reference data- but are not allowed to modify other modueles to avoid crossed dependencies between them.  
+
Up to now we have seen how to extend InfiniteERP through modules. As you remember, modules are able to add new artifacts application dictionary components, software resources and reference data but are not allowed to modify other modules to avoid cross-dependencies between them.
  
But there is a special type of modules -Industry Templates- that can include changes to other modules within it. It is done through configuration scripts. A configuration script is a collection of changes that your Industry Template does in other modules included in the Industry Template.
+
But there is a special type of modules Industry Templates that can include changes to other modules within it. It is done through configuration scripts. A configuration script is a collection of changes that your Industry Template does in other modules included in the Industry Template.
  
 
Create a configuration script is straightforward. You don't need to manually edit it but the system will generate it automatically as you go. You only need to create an Industry Template in your instance. You can only have one Industry Template "in development" at a time and any change you do will be included in the configuration script of that Industry Template.
 
Create a configuration script is straightforward. You don't need to manually edit it but the system will generate it automatically as you go. You only need to create an Industry Template in your instance. You can only have one Industry Template "in development" at a time and any change you do will be included in the configuration script of that Industry Template.
  
If you want to know more about how to create Industry Templates and configuration scripts, you can check out [[How_To_Create_a_Configuration_Script|this]] document.
+
=== Development Tasks ===
 +
 
 +
See [[Development Build Tasks]] for a complete explanation of all available development tasks.
 +
 
 +
== Advanced Concepts ==
 +
 
 +
This section explains in detail some advanced concepts of InfiniteERP Modularity. It is not strictly necessary to read all these details, but it is worth doing it — it will help avoid mistakes when creating your modules.
 +
 
 +
=== Version Numbers and How Dependencies and Includes are Managed ===
 +
 
 +
Different releases of an InfiniteERP module are identified with a '''version number'''. An InfiniteERP Version Number is a string of up to 10 characters following the format <code>x.y.z</code> where:
 +
 
 +
* <code>x</code> is a number indicating module generation (e.g., very relevant changes in functionality, user interface or technology)
 +
* <code>y</code> is a number indicating major release (e.g., new features available on a regular basis)
 +
* <code>z</code> is a number indicating minor release. Minor releases should not add any new functionality but just fix bugs within its major release with the objective of increasing stability
  
=== Development tasks ===
+
A major release is identified by the two first digits (<code>x</code> and <code>y</code>). For example, core <code>3.0.13642</code> and core <code>3.0.13921</code> are two different minor versions within the core 3.0 major version.
Read this [http://wiki.openbravo.com/wiki/Build_Tasks document] to get a complete explanation of all available development tasks.
 
  
== Publish the .obx file of a Module ==
+
Modules have to declare any dependencies between them and all of them must depend finally on the core module. Dependencies are declared to a particular major version of a module or a range of major versions, starting from a concrete minor version. For example, module A depends on core 2.50 or module B depends on any version of module A from version 1.0 to version 1.6.
Once you have finished developing your .obx file, you can publish it to the central repository.
 
#If you haven't exported your module yet, do
 
#:<pre> ant export.database</pre>
 
#Package your module using the following ant command, where ''yourModuleJavaPackage'' is the java package you defined in your module:
 
#:<pre> ant package.module -Dmodule=yourModulePackage</pre>
 
#Follow the steps defined in [[How_to_publish_a_Module#Publish_Version|Publish Version]] document.
 
  
== Advanced concepts ==
+
Usually a major release matures in a process through three phases of increasing stability: alpha, beta and production. Many minor versions can be published in each phase but the release cannot be considered stable enough to build something on top of it until the beta phase is reached. You should not develop a module that depends on an alpha version of another module to avoid instabilities inherent to this stage.
This section explains in detail some advanced concepts of Openbravo Modularity. It is not strictly necessary you to read all these details but it is worth to do it, it will help to avoid mistakes when creating your modules.
 
  
 +
To improve maintainability, minor versions of modules are not taken into account when managing dependencies. It means that a module should be compatible with any minor version of the major version it depends on. It causes some limitations on what developers can do when working on a minor version but highly improves maintainability by minimizing the effort of checking dependencies. You only need to review if your module remains compatible with a module it depends on when a major version of that module is released.
  
=== Version numbers and how dependencies and includes are managed ===
+
To enforce this behavior, it is of paramount importance to clearly state what changes are forbidden within a minor version and to enforce them before publishing. The general rule is that the public API of the module should not change, and it can be expressed in more detail with the following set of not allowed changes within a minor version:
  
Different releases of an Openbravo module are identified with a ''version number''. An Openbravo Version Number is an string up to 10 characters lenght following the format x.y.z where:
+
* '''Data model'''
*x is a number indicating module generation (eg. very relevant changes in functionality, user interface or technology)
+
  * Add a mandatory column in a table without a default or onCreatedDefault. New not-nullable columns are allowed only if they have a corresponding default or onCreatedDefault value
*y is a number indicating major release (eg. new features available in a regular basis)
+
  * Change the datatype or reduce length/precision in a column
*z is a number indicating minor release. Minor releases should not add any new functionality but just fix bugs within its major release with the objective of increasing stability
+
  * Remove a column
 +
  * Rename a column: it is equivalent to remove and create that column
 +
  * Add a new constraint to a table that was not previously enforced by the application
 +
* '''Business logic'''
 +
  * Changes in the signature of public methods/procedures/webServices: method name, number and type of parameters, return type and thrown exceptions
 +
  * Changes on expected functional behavior (e.g., meaning of a particular column/attribute, etc.)
 +
* '''Navigation'''
 +
  * Changes in the URL's for direct navigation to web components (windows, reports, etc.)
  
A major release is identified by the two first digits (x and y). For example, core 3.0.13642 and core 3.0.13921 are two different minor versions within the core 3.0 major version.
+
These restrictions make the fixing bugs exercise more difficult but are a key factor to create a maintainable ecosystem. They should be guaranteed during the beta and production phase of any release of any module. During the alpha phase — when bug fixing activity is high — you could break this rule to get some flexibility and taking into account that there should not be any other module depending on it.
  
Modules have to declare any dependencies between them and all of them must depend finally on core module. Dependencies are declared to a particular major version of a module or a range of major versions, starting from a concrete minor version. For example, module A depends on core 2.50 or module B depends on any version of module A from version 1.0 to version 1.6. In a similar way Packs and Industry Templates declare the modules (including other packs and Industry Templates) that are included within them. In this case ranges are not supported, just a major version of a module can be included in a Pack/Industry Template. Be aware that both dependencies and includes use a full version number (x.y.z) to identify the version, minor version is taken into account to define the starting version of the dependency, but it is not for the ''to version'' field. In this case, the minor version (.z) is used just for keeping track of the actual release that was used when the module was developed.
+
==== Dependency Types ====
  
Usually a major release matures in a process through three phases of increasing stability: alpha, beta and production. Many minor versions can be published in each phase but the release can not be considered stable enough to build something on top of it till the beta phase is reached. You should not develop a module that depends on an alpha version of other module to avoid instabilities inherent to this stage.
+
Dependency type is defined by the '''Dependency Enforcement''' field, the possible values it can take are:
  
To improve maintainability minor versions of modules are not taken into account when managing dependencies. It means that in the previous example module A should be compatible with any minor version of core 2.50 (it is a good idea to specify also the minor version the module was developed in, to avoid the need to test it in earlier minor versions). It causes some limitations on what developers can do when working on a minor version but highly improves maintainability by minimizing the effort of checking dependencies. You only need to review if your module remains compatible with a module it depends on when a major version of that module is released.
+
* '''Major Version''': This is the default enforcement. First Version is the first minor version the dependency is compatible with. In case Last Version is defined, it defines the latest compatible major version. If Last Version is blank or it is within the same major version First Version is in, the compatibility is defined for all versions in the same major version.
 +
* '''Minor Version''': In case both First Version and Last Version are defined, the compatibility is from the minor version in First Version to the minor version in Last Version.
 +
* '''None''': There is no restriction between major versions; First Version defines the first compatible minor version and the compatibility is for all versions higher than this one including major versions. This type should normally not be used.
  
To enforce this behavior it is of paramount importance to clearly state what changes are forbidden within a minor version and to enforce them before publishing. The general rule is that the public API of the module should not change, and it can be expressed in more detail with the following set of not allowed changes within a minor version:
+
==== User Editable Enforcement ====
*Data model
 
**Add a mandatory column in a table without a default or oncreatedefault. New not-nullable columns are allowed only if they have a corresponding default or oncreatedefault value, which can be applied to existing records without this column. You can find more information about oncreatedefaults [[How_to_define_an_on_Create_Default|here]]
 
**Change the datatype or reduce length/precision in a column
 
**Remove a column
 
**Renaming a column: it is equivalent to remove and create that column
 
**Add a new constraint to a table that was not previously enforced by the application. Constraints to avoid wrong behavior are allowed but should be warned.
 
*Business logic
 
**Changes in the signature of public methods/procedures/webServices: method name, number and type of parameters, return type and thrown exceptions
 
**Changes on expected functional behavior (eg. meaning of a particular column/attribute, etc.)
 
*Navigation
 
**Changes in the URL's for direct navigation to web components (windows, reports, etc.)
 
  
These restrictions make the fixing bugs exercise more difficult but are a key factor to create a maintainable ecosystem. They should be guaranteed during the beta and production phase of any release of any module. During the alpha phase -when bug fixing activity is high- you could break this rule to get some flexibility and taking into account that there should not be any other module depending on it.
+
Module owner can define whether the enforcement is overwriteable by user. By default it is not. In case it is possible to overwrite the module dependency's enforcement, user will be able to set a different enforcement for this dependency in his instance.
  
==== Dependency types ====
+
=== Model - Implementation Concept ===
  
Dependency type is defined by the ''Dependency Enforcement'' field, the possible values it can take are:
+
<code>AD_Model_Object</code> is a table in the InfiniteERP Application Dictionary to link Application Dictionary components and the class (servlet) that implement that object. So this table is a mapping between the logical side (AD components) and the physical side (classes). It is useful for two main reasons:
*'''Major Version''': This is the default enforcement and works as described above.
 
**''First Version'' is the first minor version the dependency is compatible with. So if first version is 1.1.5, it will be compatible with all the 1.1.x minor versions starting from 1.1.5, but not with any other major version such as 1.2.0, unless ''Last Version'' is defined.
 
**In case ''Last Version'' is defined, it is only taken into account if it is a different major version than the first version, in this case it defines the latest compatible major version, but its minor version is not taken into account. For example if the dependency is defined from 1.1.5 to 1.3.6, the module will be compatible with all 1.1.x starting from 1.1.5, with any 1.2.y version and with any 1.3.z (including minor versions of 1.3 higher than 1.3.6).
 
**If ''Last Version'' is blank or it is within the same major version ''First Version'' is in, the compatibility is defined for all versions in the same major version ''First Version'' is in starting from the minor version ''First Version'' defines.
 
*'''Minor Version''': In case both ''First Version'' and ''Last Version'' are defined, the compatibility is from the minor version in ''First Version'' to the minor version in ''Last Version'' (even they belong to the same major version). If ''Last Version'' is blank, the only compatible version will be the one defined by the ''First Version''.
 
*'''None''': There is no restriction between major versions, ''First Version'' defines the first compatible minor version and the compatibility is for all versions higher than this one including major versions. This type should normally not be used.
 
  
===== User Editable Enforcement =====
+
1. It allows to implement in a generic way rules that apply to all AD components like security, navigation and others
 +
2. It is the mechanism to automatically populate the <code>web.xml</code> file where classes (servlets) are declared
  
Module owner can define whether the enforcement is overwriteable by user. By default it is not.
+
There is a small number of exceptions to this description: some servlets that are deployed in the InfiniteERP context but are not linked to any AD component, such as the DataGrid or the AuditInfo servlets. They are invoked from manual or standard components (windows, forms, etc.) through HTTP requests by hardcoding their URL-mapping in the request.
  
In case it is possible to overwrite the module dependency's enforcement, user will be able to set a different enforcement for this dependency in his instance being this value the used to calculate dependencies.
+
By using modules, the deployment of any type of optional content in an InfiniteERP instance, including additional entries in the <code>web.xml</code> file of the InfiniteERP context, is allowed. This is done through the <code>AD_Model_Object</code> table. Developers can create entries in this window not linked to any AD component. To support any type of web.xml content (servlet, listeners, filters, etc.) a new column is added to the <code>AD_Model_Object</code> to represent the type of web.xml entry that the developer is adding.
  
Users can select the enforcement for ''User Editable Enforcement'' dependencies from the ''Settings'' tab in ''Module Management'' window.
+
With this extension the <code>web.xml</code> file in the InfiniteERP context is extensible through modules.
  
=== Model - Implementation concept ===
+
== Example on How to Create Your Module ==
AD_Model_Object is a table in Openbravo Application Dictionary to link Application Dictionary components and the class (servlet) that implement that object. So this table is a mapping between the logical side (AD components) and the physical side (classes). It is useful for two main reasons:
 
# It allows to implement in a generic way rules that apply to all AD components like security, navigation and others.
 
# It is the mechanism to automatically populate the web.xml file where classes (servlets) are declared. The AD_Model_Object_Mapping is an utility to create the mapping entries in the web.xml file.
 
  
There is a few number of exceptions to this description: some servlets that are deployed in Openbravo context but are not linked to any AD component, such us the DataGrid or the AuditInfo servlets. They are invoked from manual or standard components (windows, forms, etc.) through http requests by hardcoding its url-mapping in the request. It can be interpreted still as a mapping of actual classes that implement a functionality that is not described in current Openbravo model, although it may be in the future.
+
Now it is time to go practice. See [[How to Create and Package a Module|How to Create and Package a Module]] which guides you step by step on how to create your first module.
  
By using modules, the deployment of any type of optional content in an Openbravo instance, including additional entries in the web.xml file of openbravo context, is allowed. This is done through the AD_Model_Object table. Developers can create entries in this window not linked to any AD component. To support any type of web.xml content (servlet, listeners, filters, etc.) a new column is added to the AD_Model_Object to represent the type of web.xml entry that the developer is adding. They can also declare a set of mappings for the entry and a set of parameters if needed.
+
== See Also ==
  
The module of a AD_Model_Object entry is calculated with the following rule: if it is linked to any AD component then the module is the one assigned to that AD component, otherwise the module is the one assigned to the AD_Model_Object record itself.
+
* [[How to Create and Package a Module]]
 +
* [[How to Publish a Module]]
 +
* [[Data Access Layer]]
 +
* [[Application Dictionary]]
 +
* [[Development Build Tasks]]
  
With this extension the web.xml file in the openbravo context is extensible through modules.
+
== References ==
  
More information about the Openbravo model object mapping can be found [[Model_Object_Mapping|here]].
+
* [https://docs.etendo.software/developer-guide/etendo-classic/concepts/modularity-concepts/ Modularity Concepts — Etendo Documentation]
  
== Example on how to create and package your module ==
+
----
  
Now it is time to go practice. You can follow this [[How_To_Create_and_Package_a_Module|howto]] that will guide you step by step on how to create and package your first module.
+
''This page is a derivative of [http://wiki.openbravo.com/wiki/Modularity_Concepts Modularity Concepts] by [http://wiki.openbravo.com/wiki/Welcome_to_Openbravo Openbravo Wiki], used under [https://creativecommons.org/licenses/by-sa/2.5/es/ CC BY-SA 2.5 ES]. This work is licensed under [https://creativecommons.org/licenses/by-sa/2.5/ CC BY-SA 2.5].''
  
[[Category:Concepts]]
+
[[Category:Developers Guide]]
 +
[[Category:Documentation ERP]]

Latest revision as of 00:03, 21 September 2026

Back button.png   Back to Main Page


Modularity Concepts

This document contains an overview of the process of developing InfiniteERP Modules. It describes the concepts, artifacts and processes involved in building, packaging and distributing modules for InfiniteERP.

Overview

InfiniteERP supports the concept of Modularity: the ability for developers to build, package and distribute Extension Modules, and for users to install, uninstall and update Extension Modules.

An Extension Module is a piece of additional functionality that can be deployed optionally and independently on top of InfiniteERP. Examples of modules are: additional reports, additional windows, connectors, content packs (translations, chart of accounts, list of tax codes, product categories, etc).

The objectives of modularity are:

  • Making it easier to contribute to InfiniteERP by allowing distributed and decoupled development and maintenance of optional features
  • Providing the Community with a rich set of extensions to meet their unique business requirements without bloating the core product
  • Shortening the implementation cycles by enabling system integrators to develop micro-vertical templates

Concepts

Before you start, it is required to understand some concepts. These concepts are described in detail in the following sections.

Types of Extension Modules

There are three types of Extension Modules:

  • Modules: Base content container. Within a Module, you can include all types of artifacts but Configuration Scripts: Application Dictionary components, Software Resources and Reference Data. Modules are the way to add new elements to InfiniteERP. In a Module, you cannot modify elements of other modules — including core. The reason for that is to avoid cross-dependencies between them.
  • Bundle: a Bundle is a collection of modules and no more. They are intended to simplify deployment and to encourage fine-grained modules. Special bundles are localization and verticalization bundles.
  • Templates: a combination of a Module and a Configuration Script that is able to modify the behavior of AD components in Modules.

The three of them are generically referred to as Modules.

Artifacts in an Extension Module

There are four types of artifacts that can be included in an Extension Module:

  • Application Dictionary Components: Metadata that describes InfiniteERP such as Windows, Tabs, Fields, Messages, etc.
  • Software Resources: InfiniteERP components not expressed as metadata such as `XML` definition of database schema objects, Java classes, XML files, etc.
  • Reference Data: Business information referred by transactions and that tend not to change frequently such as Charts of accounts, tax codes, banks, product categories, etc. They can be defined at system, client or organization level.
  • Configuration Script: Changes in Application Dictionary Components applied to other modules to support a specific set of business processes, such as hide / show tabs or fields, replace standard processes, etc. Only meaningful changes are allowed.

The InfiniteERP platform itself cannot be modified through modules. In particular, you are not allowed to modify WAD (src-wad code) in a module. It should not be a limitation since the platform is designed to be extensible.

Packaging and .zip and .jar Files

All the content of a module — code, utility files, data — is contained in a separate folder for each module. All the content in that folder is related to, and only related to, that module. There is a folder within the main InfiniteERP folder called modules where all the modules that you have installed or developed are located. For each module there is a folder identified by the Java package of the module. In that folder the source code structure of InfiniteERP (config, src, src-db, lib, etc.) is replicated as required to store the content of the module.

Modules are distributed as .zip or .jar files which are compressed files of the module folder.

InfiniteERP Repository

Supported InfiniteERP modules are published as packages. Licensed developers and partners with access can browse and download packages available there.

More information about module publishing can be found in How to Publish a Module.

Introduction to the Process of Developing a Module

The process of developing a Module has three main steps:

1. Register your Module in the Application Dictionary 2. Develop the artifacts included in your Module. Depending on the functional specification and technical design of your module it might include only one type of artifacts or a combination of them. In the following sections each type of artifact is described in detail.

Step 1 is common to all types of modules. Step 2 depends on the requirements of your module. It has not significantly changed from the way you have developed InfiniteERP code in previous releases.

Be aware that from now on every piece of InfiniteERP code belongs to a module (you can see, for example, that the InfiniteERP distribution in fact includes several modules, and one of them is Core). You should do all your new developments through modules, including your customizations. Still you can do changes directly in other modules — including InfiniteERP core — but it is highly recommended not to do that. Maintenance will be dramatically better if you keep your changes isolated by doing them through modules, as you can update individual modules without doing any changes to other ones (so, for example, you can update the InfiniteERP distribution modules without doing any changes to your modules).

Register a Module

The first thing you have to do is to create a new Module entry in the Module Window within the Application Dictionary menu folder.

There are some details that you need to be aware of:

  • Each module has its own native (base) language. In the following sections the translation process is described; by now just choose the language you prefer to develop the UI of your module. Of course, if you choose English it will be easier to disseminate (e.g., to find people to translate it to other languages).
  • Name, description and help are the properties used to explain in the repository what your module is. Write them in natural style using the native language you have chosen.
  • The Version Number is composed by three numbers separated by two dots to match the InfiniteERP template for version numbers. In this field, you need to have the current version you are working on (there might be multiple versions of your module).
  • The Java package is a unique identifier of your module and has to match the Java packaging names rules as described in the Java specification. You need to carefully set this value because you are not allowed to change it once your module is published. If your module includes Java files, they have to be packaged within your module Java package or in subpackages within it. Examples of Java packages for a module are com.yourcompany.yourPackage, org.yourfoundation.yourPackage.yourSubpackage, etc. You should name your modules with a Java package which doesn't start by com.infiniteerp or org.openbravo, but with an identifier of you, your company, or the project you belong to.
  • Choose the type (Module, Pack, Template) as described in the Concepts section.
  • In development is a boolean property to let the system know that you are developing on that module. Only modules in development will be exported by development tools and the System will raise an error if you try to modify some component on a module that is not in development.
  • Although you might have more than one module in development, you can set which one is chosen by default when developing. This is just a way to set a default value for the module when you edit the Application Dictionary.

It is recommended to restart the instance after changing the development status of a module in order to update the cache's status. Also note that production instances cannot have modules in "In development" status.

  • Some modules will not have UI (e.g., a connector to a banking system or a web service) so there is no need to translate them.
  • If your module is a translation module of another module you have to check this flag to allow users to search for translations.
  • If your module has a Chart of Accounts, you have to check this flag to allow the System to use them during the Initial Client/Organization Setup processes.
  • If your module has standard Reference Data you have to check this flag to allow the System to use them during the Initial Client/Organization Setup processes.
  • You have also to choose the license you are using to distribute your module. Choose one license type from the drop-down list and write the license agreement that will be shown to the user when installing or updating your module.
  • The author of the module will be shown to the User when installing. Also the User will be able to navigate from there to the module URL.
  • If you are working on a new version of your module you can explain what are the changes this new version includes (fixed bugs in minor versions, new features in major ones) in the Update information field.

The Include tab is intended only for Packs and Industry Templates. In this tab, you include all the modules that are members of the Pack. You can only choose from the ones that you have installed in your instance. You have to provide the Version Number for each of them.

The Dependency tab is intended only for Modules. In this tab, you declare all the Modules that your Module depends on. It is of paramount importance that you declare them properly since the system will check that dependencies are met when the User installs or updates your module. It is also important to declare them as soon as you are aware of that because some tools and processes in the development process take into account dependencies and the result might be wrong if they are not declared when developing your module. Typically, a module will depend on User Interface Application and in turn, it has a dependency on InfiniteERP core and eventually on other modules.

There is no need to edit the Translation tab. It is a tool for translators.

If your Module includes a table in the Application Dictionary then you need to register one (or many) data packages in your Module. For a full description on how packages are used, visit the DAL developers manual. For each package you have to set the next properties:

  • Name, that will be used in the XML entities of tables assigned to it
  • Description, used to explain what your package is for
  • Java package, that has to match the Java packaging names rules. It should be equal to Module package name (if there is only one package) or a subpackage of it.

If your Module includes any database schema object (a table, a stored procedure, etc.) or an AD message then you need to define the DB_Prefix. This is a string of up to seven characters. All your database schema object names need to start with this prefix so it needs to match Oracle and PostgreSQL naming requirements (case insensitive and stored in uppercase, alphanumeric characters and start by an alphabetic character). You can only register one DB_Prefix; just the InfiniteERP core Module is allowed to have more than one. DB_Prefix is needed to guarantee that there are no naming clashes when installing modules.

Once you have completed the set up of your module, it is needed to ensure that your DB_Prefix and your Java package are not already registered by other Modules, and it is important to do it even if you don't plan to publish your module.

Naming

It is of paramount importance to use proper names for modules. Especially for Java Package and DB Prefix. This is the only warranty that there will not be conflicts when installing other modules.

Java Package

Java Package should be a valid unique Java Package. These are instructions from Java.sun.com:

You form a unique package name by first having (or belonging to an organization that has) an Internet domain name, such as sun.com. You then reverse this name, component by component, to obtain, in this example, com.sun, and use this as a prefix for your package names, using a convention developed within your organization to further administer package names.

Example:

If your company is named Foods & Beverages and you have an Internet domain called fandb.com, all your Java packages should start by com.fandb. If you create a CRM module, its Java package could be com.fandb.crm.

Note: Java packages starting by com.infiniteerp or org.openbravo should only be used by modules distributed by InfiniteERP.

DB Prefix

It is a good practice to use a short prefix for your company followed by a prefix for your module. Following the previous example, all your DB prefixes could start by FB, and the one for the CRM module could be FBCRM.

About customization modules: Usually customization modules are not intended to be published in a public repository. In this case, DBPrefix should start with CUST. Modules with these kinds of DBPrefixes cannot be registered in a public repository but are collision safe because no other module in a public repository can use this DBPrefix. This is an important decision to be taken before starting the module development: in case there is any chance of publishing the module at some moment, it should follow the standard rule; if it is absolutely sure that it will not be published you can use CUST.

Development of Module Artifacts

As stated in the Concepts section, there are four types of artifacts: Application Dictionary Components, Software Resources, Reference Data and Configuration Script. The requirements of your module and its technical design will define the needed artifacts to build your module.

Application Dictionary Components (AD Components)

Most of AD components can be included in your module but a few exceptions that are explained later in this section. The general rule to describe how Application Dictionary components are included in your module is simple: set the module field of that component to your module. If you only have one module in development or you are working in your default module it will be done automatically by the system.

An AD component will only be editable when the module it belongs to is in development, or if there is an Industry Template in development in the system. If you change a property in an AD component that is not in development the system will raise an error to avoid you to perform unintended changes.

Translations are managed in a particular way and you don't need to care about translations when developing. But remember that your module has a native (base) language so the UI components (Windows, tabs, fields, elements, messages, textInterfaces, etc.) that you develop have to be created in that language.

Access information is not included in modules, so you can forget it when developing your module.

Table and Column

Registering tables in the AD is the first exception to the general rule. Tables are not assigned directly to a module but to a data package in a module. It is needed by the DAL to properly manage packaging of generated entities and XML naming. Only packages of "in development" modules are available when you edit a table. The module of a table is the module of the package of a table.

Columns are assigned by default to the module of their table. But you might want to add in your module a column within a table in a different module (e.g., add a new column to the M_Product table in the core module). To do that you are forced to use a naming rule for that column: its physical name (ColumnName property) has to start by the prefix EM_XXX_ where XXX is your module DB_Prefix (taking into account that the full column name must not be greater than 30 characters). EM stands for External Module. The same rule is applicable for the Name property which is used to generate DAL properties, therefore must be unique among different modules.

Windows, Tabs and Fields

Windows, Tabs and Fields follow the general rule. The three of them are linked to a module. By default, when you add a tab to a window, it will be linked to the module of its window and, when you add a field to a tab, it will be linked to the module of its tab. This is true but when the window or tab modules are not in development. Then the defaulted module will be proposed.

When editing the field sequence the system will guarantee that you do not change the sequence number of fields that are not in your module, so if you add a new field in a tab of another module the sequence number of the original fields will not be modified.

The tab class and mapping is automatically managed by the system and you do not need to take care about it.

Reference

There are four types of references: Data type, List validation, Search validation and Table validation. Only List validations and Table validations can be included in a module different to InfiniteERP core. Data types and Search validations will be supported in modules in future releases.

All the values included in a List validation are included in the module where the List validation is defined. You cannot add in your module new values to a List validation in a different module nor modify the values included in it.

Report and Process

Reports and Processes follow the general rule. You can declare a new process or report in your module by just creating a new entry in the Report and Process window and linking that entry to your module. All parameters in a Report or Process will be included in the module where the Report or Process is declared.

For manual report and processes it is necessary to define the process mapping, this mapping can be anything within the module's package, for example /org.mycompany.mymodule.report/MyReport.html.

Form

Forms follow the general rule too. You can declare a new form in your module by just creating a new entry in the Form window and linking that entry to your module.

For forms it is necessary to define the form mapping, this mapping can be anything within the module's package, for example /org.mycompany.mymodule.form/MyForm.html.

Message

Messages follow the general rule but with an additional detail you need to revise. You can declare a new message in your module by just creating a new entry in the Message window and linking that entry to your module, and the search key of the message has to start by your module DB prefix (to avoid clashes between messages from different modules). It means that you cannot include in your module a message with a numeric search key to be raised by a PL/SQL object through the RAISE_APPLICATION_ERROR function.

Text Interfaces

Text interfaces window usually is not edited manually but entries are automatically generated by the translation process when it parses files to be translated. This process takes into account the packaging of the file being translated and the text interface entry is properly assigned to the module. This process should be transparent for developers but you can browse the entries that your manual developments have created and edit them.

Element

Elements are usually automatically generated by the Synchronize terminology process when you create new columns. This process takes into account the name of the columns that you have included in your module and searches in your module and the modules your module depends on for an element with that column name. If it is found, your column will be linked to that element; if not, a new element will be created in your module. This process should be transparent for developers but you can browse the elements included in your module and edit them.

Field Category, Auxiliary Input, Callouts and Validations

These four Application Dictionary components follow the general rule too. You can declare a new component of them in your module by just creating a new entry in the proper window and linking that entry to your module.

Auxiliary input name must start with the module's DBPrefix.

Model - Implementation Mapping

Model - Implementation mapping is a generalization of the Model-Object concept that was present in previous releases. Through this new window you can include in your module the entries you need to add to the web.xml file of the InfiniteERP context.

Model - Implementation mappings follow the general rule. You can declare a new entry in your module by just creating a new record in the Model - Implementation mapping window and linking that entry to your module. All mappings and parameters assigned to it will be included in the module where the Model - Implementation mapping is declared.

Software Resources

To develop your module you may require to include some software resources. Software resources are InfiniteERP components not expressed as metadata such as XML definition of database schema objects, Java classes, JAR libraries, XML files, etc. All you need to add to your module has to be packaged within InfiniteERPMainFolder/modules/yourModuleJavaName. Within this folder, you have the standard InfiniteERP folders to hold your software resources (src, src-db, lib, etc).

The build process of InfiniteERP takes into account the source code structure that is split into modules. Be aware that this concept is completely different from the srcClient that was used in previous releases: you are not allowed to physically overwrite a file in the InfiniteERP core distribution. In fact, the packaging of your software resources should be located in com.yourCompany.xxx or org.yourCompany.xxx so you will not use com.infiniteerp.xxx to package your code any more.

Similarly to AD components, although this general rule for packaging is applied to all software resources there are some details for each type of software resource (Database schema objects, Java classes, JAR libraries, web static content, etc.) that you need to be aware when developing your module.

Database Schema Objects

The typical flow to add a new database schema object (table, column, constraint, index, trigger, view, stored procedure, function) or modify it in InfiniteERP is as follows:

  • A developer uses her/his preferred tool as database client for development in Oracle or PostgreSQL
  • Using SQL scripts or GUI tools she/he creates or modifies the database schema object in the database following InfiniteERP standards
  • If the database schema object is mapped with any Application Dictionary (Tables & Columns, Reports & Processes) then the developer imports the new DB schema object from the database to the Application Dictionary. This process adds some new lines in AD tables. After that, the developer usually adjusts the imported information — e.g., running the synchronize terminology process — and completes AD information to fully describe the solution she/he targets. It might require as well to create some InfiniteERP code (Java files, XSQL files, etc.) to complete the solution
  • Once the solution is fully described, the developer builds the system to test that it is working as desired
  • The last process is to export the database to .xml files through DBSourceManager. This tool exports every database schema object to a .xml file that uses a common syntax for both Oracle and PostgreSQL so you can have different development environments committing to the same line of code. Application Dictionary data is also exported in this process. So there are two different types of .xml files exported by DBSourceManager: model (DB schema objects) and sourcedata (Application Dictionary metadata)

From a modularity perspective, there is no need to do any additional task to take care of Application Dictionary metadata since it is managed by the system as described in the previous Application Dictionary Components section. But to avoid naming clashes in the database and to allow DBSourceManager to know the module of not-mapped database schema objects it is required to follow the next naming rule for database schema objects:

  • All main objects (tables, triggers, views, functions, stored procedures) have to start by your module DB prefix followed by an underscore ("_") symbol (e.g., MYMOD_MYTABLE, MYMOD_MYPROCEDURE, etc.)
  • Every object (tables, constraints, indexes, functions, triggers) needs to have a unique name in the database. To avoid any kind of duplication, constraint and index names in particular need to start with their table name. This ensures that there will be no name duplication in the whole database
  • Subparts of main objects (columns, constraints, indexes) are supposed to belong to the module of the main part except if their name starts by "EM_" + DB prefix + "_" (e.g., EM_MYMOD_MYCOLUMN, EM_MYMOD_MYCONSTRAINT, etc.). EM stands for External Module. So you can use standard column names in your tables (e.g., C_BPARTNER_ID, M_PRODUCT_ID, NAME, etc.) but if you want to add in your module a "part" (column, constraint, index) to a table in another module you need to use the prefix "EM_" + DB prefix + "_" for the name of that part

Following this simple rule, you can include in your module as many database schema objects as you want. But be aware that you cannot modify database schema objects in other modules as it would break the main rule: "a module cannot modify components in other modules."

When DBSourceManager exports the database, it will only take into account modules "in development"; the other ones will not be exported. The exported XML files will be located within the src-db/database folder within the module folder.

Naming Exceptions: It is possible to define database schema objects within a module that do not follow the naming rules explained above. This is specially useful in order to move to modules existent InfiniteERP instances in older versions. It is important to note that this feature should not be used for new developments in general. If a module contains a naming exception, it will not be possible to publish it to a public repository, because it would not be possible to guarantee that the object defined as a naming exception would not collide with another object defined in a different module.

When a database schema object is defined as an exception for a module it is exported to that module instead of to the one that should be according to its name and the naming rules.

Exceptions are defined in Application Dictionary > Module > Module > Naming Exceptions tab which contains two fields:

  • DB Object Type: Defines the database object type (table, function, index...)
  • Object name: It is the database object name. Note that it is the name in the database, not in Application Dictionary

Extension Points: Extension Points allow the developer to attach execution code to predefined specific points inside InfiniteERP PL/SQL functions. This functionality can be used to extend the functionality of some Core functions, without overwriting them in any way. This way of extending the functionality fits very well with Modularity, as it allows extension but also keeps maintainability and upgradeability.

Java Classes, Other InfiniteERP MVC Objects and JAR Libraries

Java classes, other InfiniteERP MVC objects (HTML, XML and XSQL files) and JAR libraries follow the general rule to add software resources in your module. You have to package this code within the src folder located in your module folder.

When InfiniteERP builds the system it will dynamically add to its Java project all the src folders within all installed modules as Java resources of the project. It uses an intermediate location, build folder, to generate code from XSQL files and to compile all Java resources and put them together. You can include in your module JAR libraries made by you or by any other third party and use them along your code. All JAR libraries included in the lib/runtime folder inside your module, are added to the classpath at compilation time and finally deployed to the InfiniteERP context.

After the generation of code and compile process the build process deploys all the content to the InfiniteERP context in the servlet container. There are two modes of deployment — class and war — that are explained in Development Build Tasks.

Web Static Content (CSS files, images, JavaScript)

If you need to add some web static content (CSS, images and JavaScript) to your module you have to place these resources in the web folder of your module, within a folder named as the Java package of your module to avoid clashes of files when deploying resources from different modules.

When the system is built all files in the web folder of your module are copied to WebContent and from there it is deployed to the InfiniteERP context in a standard way so these resources can be accessed from the pages in your module by referencing them.

You can also reference other web static content resources included in core or other modules. In that case, remember to explicitly declare the dependency to that module.

Config Files

You might also need to include some configuration files in the config folder of your module. These files will be copied to WebContent/WEB-INF when the system is built and deployed to the InfiniteERP context.

To avoid clashing of files deployed by different modules, files within the config folder should be prefixed with the PackageName of the module.

Reference Data

InfiniteERP Modularity supports Reference Data: business information referred by transactions and that tend not to change frequently such as translations, charts of accounts, tax codes, banks, product categories, etc. They can be defined at system, client or organization level and it will define when they are loaded into the instance: System information will be loaded at installation time while Client and Organization information will be loaded during the Initial Client/Organization Setup or Enterprise Module Management processes.

Reference data modules are also versioned and can publish updates and upgrades during their life cycle.

There are three types of reference data supported: Translations, Chart of Accounts and Standard Reference Data.

Translations

Translation modules are a special kind of module. They have to be marked as "Is translation module" in the Module window. No other contents than translations are allowed in translation modules, and only translations for one module to only one language — the native language declared for the module (e.g., translation for core module to Spanish, translation for HR module to French). Translation modules only depend on the module they translate.

Create a translation module is a straightforward process. First you have to create your module as usual. Remember to define it as "translation module" and define its native language as the language you are going to translate to. Keep unchecked the other properties related to reference data (Translation required, Has chart of accounts and Has reference data). This module does not need any Includes, Data packages and DB prefix and will only depend on the module version you are translating.

Then create the main folder of your module — named as its Java package — within the modules folder. Then all you have to do is install the module you plan to translate and declare the dependency of your translation module to this module, and follow the standard translation process. Once you have completed the translation you have to copy the translated XML files of the translated module — only these ones — to referencedata/translation folder within your module folder, and package it as usual.

Translation information is always at System level. When a translation module is installed the process takes care of all details to import a translation pack: it will mark the Language as System Language if it was not and will load all translations in the InfiniteERP Application Dictionary.

Chart of Accounts (CoA)

Typically you should add just one Chart of Accounts in your module, although you can create as many modules including CoA as you want and then put them together in a pack if needed. Chart of Accounts are stored in a particular .csv file.

It is easy to create a module including a Chart of Accounts once you have prepared the .csv file. All you need to do is create a new module and mark as checked the Has a chart of Accounts property. Keep unchecked the other properties related to reference data. This module does not need any Includes, Data packages and DB prefix and will only depend on the core version you are using (the structure of the .csv file is defined in core).

Then create the main folder of your module — named as its Java package — within the modules folder. Within the main folder you have to create the subfolder referencedata (all in lower case) and within it the folder accounts and place your .csv file there. Remember that folders are case sensitive.

Now your module is ready to be packaged. Execute the Ant task package.module -Dmodule="yourModuleJavaPackage" and it will create an .obx file that is ready to be published or distributed.

Chart of Accounts are always at Client/Organization level so nothing happens when you install this type of modules but just that the chart of accounts is available to be applied to new clients (during Initial Organization Setup), new organizations (during Initial Organization Setup) or to existing Client/Organizations (by Enterprise Module Management).

Standard Reference Data

You can also include any other data in your module through standard reference data using data sets.

First you need to create in your instance the data you want to include. It could be taxes for a particular country, product categories or a collection of alerts for a particular industry or any other data. You can combine different data from different tables in your module.

After that, the next step is to create a module and mark as checked the Has reference data property. Keep unchecked the other properties related to reference data. Complete the Reference data description with information about the data you are including. This module does not need any Includes, Data packages and DB prefix and will depend on the module versions that define the data structure you aim to include.

Then you have to create within your module as many data sets as you need to define your data. A data set is a collection of data defined by the tables where those data are stored, the rows included — defined through a filter clause for each table — and the columns you want to include for each table.

You can create data sets in the Data Set window within the Application Dictionary menu folder.

There are some details you need to be aware when creating data sets:

  • The data set should be assigned to your module in which you will distribute those data
  • Data access level defines the level at which data will be imported and when:
 * System only: imported at System level at installation time. Only tables with System only, System/client and All data access level are allowed
 * System/client: imported at Client level during "Initial Client Setup" or "Enterprise module management" processes. Only tables with System/client, Client/Organization and All data access level are allowed
 * Client/organization: imported at Client or Organization level during Initial Client Setup, Initial Organization Setup or Enterprise module management processes
 * Organization: imported at Organization level during "Initial Organization Setup" or "Enterprise module management" processes
  • Check the Export allowed field to show the Export Reference Data button. With this button, you will be able to export your data to XML files and this way include them in your .obx file

Next step is to define the collection of tables included in your data set.

Again some details you need to be aware:

  • You can add as many tables as you need in your data set
  • For each table you can add a SQL where clause to filter data in the table
  • You can include all columns in the table or declare one by one the ones you want to include
  • Typically you will not want to include audit info in your data, you can exclude audit info columns
  • By default your data set includes just the records in the data set tables matching the SQL where clause criteria. But you can define the table in your data set as Is business object. If you do it then the system will export not only the records in the table matching your SQL where clause but recursively any other record in the system that has a foreign key to these records

Now you have to define the columns included for each table.

Usually there is no need to define columns in your table since typically you want to include all of them but audit info. Sometimes you might want to exclude some other columns by checking the Excluded field.

Once you have completed the definition of all your data sets you have to export them to XML files so they are included in your .obx file when packaging your module. To do that you have to click on the Export Reference Data button in the data set header. It will create an XML file named as the data set in referencedata/standard subfolder within your module folder. Finally package it as usual by executing the Ant task package.module -Dmodule="yourModuleJavaPackage" that will create an .obx file that is ready to be published or distributed.

As described before you can also publish new versions of your reference data modules. Take into account that to ensure data consistency reference data is not deleted from the instance when applying an update/upgrade where the new data set does not include some records originally included. So instead of remove them from the data set you should inactivate them.

Advanced Topics

There are special cases that must be taken into account when including tables and columns to reference data.

All columns in dataset are always reset, when updating reference data: In case you are developing a module that contains a dataset at a System/client, Client/Organization or Organization data access level, you must take into account that every time the user updates the reference data application (through Enterprise Module Management window) all the included columns will be updated. This is useful, but also a little bit dangerous.

What can be done in order to avoid this kind of issues? Just don't include that value in the dataset, and set it through the default value of the column.

Module Scripts and Build Validations

It is possible that your module needs to check if the system complies with some specific rule before installing it. If this is the case, a Build Validation can be used to verify it. A Build Validation is basically a process, defined as a Java class, which can connect to the database and to the InfiniteERP sources, check whatever the developer wants, and finally return a result of the validation. If the result is not positive, the module is not applied in the system.

Also, it is possible that your module needs to do specific transformations to the system while installing. This changes can be of basically any kind, such as modifying some data in the system, or adding some database object which uses some Oracle or PostgreSQL specific syntax which makes it not possible to add it through the standard DBSourceManager + XML files. For this, you can use Module Scripts, which like Build Validations, are defined as a Java class which can connect to the database, and do any kind of modifications to client data.

If you want to know more about how to create Build Validations and Module Scripts, you can check How to Create Build Validations and Module Scripts. If you plan to use a module script to create a database object which uses some kind of database specific syntax or feature, you should exclude it from the DBSourceManager standard model. To learn how to do this, read How to Exclude Database Physical Objects From Model.

Configuration Script

Up to now we have seen how to extend InfiniteERP through modules. As you remember, modules are able to add new artifacts — application dictionary components, software resources and reference data — but are not allowed to modify other modules to avoid cross-dependencies between them.

But there is a special type of modules — Industry Templates — that can include changes to other modules within it. It is done through configuration scripts. A configuration script is a collection of changes that your Industry Template does in other modules included in the Industry Template.

Create a configuration script is straightforward. You don't need to manually edit it but the system will generate it automatically as you go. You only need to create an Industry Template in your instance. You can only have one Industry Template "in development" at a time and any change you do will be included in the configuration script of that Industry Template.

Development Tasks

See Development Build Tasks for a complete explanation of all available development tasks.

Advanced Concepts

This section explains in detail some advanced concepts of InfiniteERP Modularity. It is not strictly necessary to read all these details, but it is worth doing it — it will help avoid mistakes when creating your modules.

Version Numbers and How Dependencies and Includes are Managed

Different releases of an InfiniteERP module are identified with a version number. An InfiniteERP Version Number is a string of up to 10 characters following the format x.y.z where:

  • x is a number indicating module generation (e.g., very relevant changes in functionality, user interface or technology)
  • y is a number indicating major release (e.g., new features available on a regular basis)
  • z is a number indicating minor release. Minor releases should not add any new functionality but just fix bugs within its major release with the objective of increasing stability

A major release is identified by the two first digits (x and y). For example, core 3.0.13642 and core 3.0.13921 are two different minor versions within the core 3.0 major version.

Modules have to declare any dependencies between them and all of them must depend finally on the core module. Dependencies are declared to a particular major version of a module or a range of major versions, starting from a concrete minor version. For example, module A depends on core 2.50 or module B depends on any version of module A from version 1.0 to version 1.6.

Usually a major release matures in a process through three phases of increasing stability: alpha, beta and production. Many minor versions can be published in each phase but the release cannot be considered stable enough to build something on top of it until the beta phase is reached. You should not develop a module that depends on an alpha version of another module to avoid instabilities inherent to this stage.

To improve maintainability, minor versions of modules are not taken into account when managing dependencies. It means that a module should be compatible with any minor version of the major version it depends on. It causes some limitations on what developers can do when working on a minor version but highly improves maintainability by minimizing the effort of checking dependencies. You only need to review if your module remains compatible with a module it depends on when a major version of that module is released.

To enforce this behavior, it is of paramount importance to clearly state what changes are forbidden within a minor version and to enforce them before publishing. The general rule is that the public API of the module should not change, and it can be expressed in more detail with the following set of not allowed changes within a minor version:

  • Data model
 * Add a mandatory column in a table without a default or onCreatedDefault. New not-nullable columns are allowed only if they have a corresponding default or onCreatedDefault value
 * Change the datatype or reduce length/precision in a column
 * Remove a column
 * Rename a column: it is equivalent to remove and create that column
 * Add a new constraint to a table that was not previously enforced by the application
  • Business logic
 * Changes in the signature of public methods/procedures/webServices: method name, number and type of parameters, return type and thrown exceptions
 * Changes on expected functional behavior (e.g., meaning of a particular column/attribute, etc.)
  • Navigation
 * Changes in the URL's for direct navigation to web components (windows, reports, etc.)

These restrictions make the fixing bugs exercise more difficult but are a key factor to create a maintainable ecosystem. They should be guaranteed during the beta and production phase of any release of any module. During the alpha phase — when bug fixing activity is high — you could break this rule to get some flexibility and taking into account that there should not be any other module depending on it.

Dependency Types

Dependency type is defined by the Dependency Enforcement field, the possible values it can take are:

  • Major Version: This is the default enforcement. First Version is the first minor version the dependency is compatible with. In case Last Version is defined, it defines the latest compatible major version. If Last Version is blank or it is within the same major version First Version is in, the compatibility is defined for all versions in the same major version.
  • Minor Version: In case both First Version and Last Version are defined, the compatibility is from the minor version in First Version to the minor version in Last Version.
  • None: There is no restriction between major versions; First Version defines the first compatible minor version and the compatibility is for all versions higher than this one including major versions. This type should normally not be used.

User Editable Enforcement

Module owner can define whether the enforcement is overwriteable by user. By default it is not. In case it is possible to overwrite the module dependency's enforcement, user will be able to set a different enforcement for this dependency in his instance.

Model - Implementation Concept

AD_Model_Object is a table in the InfiniteERP Application Dictionary to link Application Dictionary components and the class (servlet) that implement that object. So this table is a mapping between the logical side (AD components) and the physical side (classes). It is useful for two main reasons:

1. It allows to implement in a generic way rules that apply to all AD components like security, navigation and others 2. It is the mechanism to automatically populate the web.xml file where classes (servlets) are declared

There is a small number of exceptions to this description: some servlets that are deployed in the InfiniteERP context but are not linked to any AD component, such as the DataGrid or the AuditInfo servlets. They are invoked from manual or standard components (windows, forms, etc.) through HTTP requests by hardcoding their URL-mapping in the request.

By using modules, the deployment of any type of optional content in an InfiniteERP instance, including additional entries in the web.xml file of the InfiniteERP context, is allowed. This is done through the AD_Model_Object table. Developers can create entries in this window not linked to any AD component. To support any type of web.xml content (servlet, listeners, filters, etc.) a new column is added to the AD_Model_Object to represent the type of web.xml entry that the developer is adding.

With this extension the web.xml file in the InfiniteERP context is extensible through modules.

Example on How to Create Your Module

Now it is time to go practice. See How to Create and Package a Module which guides you step by step on how to create your first module.

See Also

References


This page is a derivative of Modularity Concepts by Openbravo Wiki, used under CC BY-SA 2.5 ES. This work is licensed under CC BY-SA 2.5.