A cartridge is a code container for implementation artifacts like templates, pipelines, Java code etc. that provide business logic or technical functionality to Intershop Commerce Management (ICM).
Cartridges are the building blocks and deployment containers of an ICM application. Cartridges can be installed (deployed) on an ICM application server to make the functionality implemented by the application units available on the server.
Thus, cartridges are the standard mechanism for packaging and deploying.
Any objects and entities defined at the different architectural layers (persistence layer, business object layer, presentation layer) are distributed over a set of cartridges.
The cartridge concept provides a uniform and easy-to-handle way of integrating new code components into ICM. All new applications to extend and/or customize ICM must abide by the organizational principles that the cartridge concept imposes, no matter whether the application is simple or complex.
The following files in <IS_SOURCE>/<cartridge_name> are deployed to <IS_SHARE>/system/cartridges/<cartridge_name>/release:
Source Project | Deployed | Contents |
---|---|---|
/src/main/java | /lib/<cartridge_name>.jar | Java code (such as business objects, persistent objects, provider classes, or pipelets) |
/src/main/resources
| /lib/<cartridge_name>.jar | Non-Java code (such as orm files, additional pipelet files, DBInit and DBMigrate properties files) Cartridge properties can be located in the main/resources/cartridges folder Site content must be located in the main/resources/resources folder |
/src/test/java | Java code (unit test cases) | |
/src/test/resource | Non-Java code (unit test cases) | |
/build.gradle | The cartridge definition declaring, e.g., display name, version and build numbers, and dependencies. This will not be deployed. | |
/src/main/resources
| /lib/<cartridge_name>.jar | EDL models |
/model | EMF Metamodels | |
/staticfiles/definition | /definition | JAXB XML schemas and configuration files used as a base to generate Java classes. |
/src/main/resources
| /lib/<cartridge_name>.jar | Database initialization properties, see Concept - DBPrepare |
/src/main/resources
| /lib/<cartridge_name>.jar | Migration steps executed by DBMigrate, see Concept - DBPrepare |
/src/main/resources
| /lib/<cartridge_name>.jar | Configuration files, see Concept - Configuration |
/src/main/resources
| /lib/<cartridge_name>.jar | Component definitions, see Concept - Component Framework |
/src/main/resources
| /lib/<cartridge_name>.jar | Extensions, see Concept - Extension Points |
/src/main/resources
| /lib/<cartridge_name>.jar | Default configurations for import and export processes, see Concept - Impex Framework |
/src/main/resources
| /lib/<cartridge_name>.jar | Cartridge specific logback extension, see Cookbook - Logging |
/src/main/resources
| /lib/<cartridge_name>.jar | Localization bundles, see Concept - Localization |
/src/main/resources
| /lib/<cartridge_name>.jar | Pagelets provided by this cartridge, see Concept - CMS - Overview |
/src/main/resources
| /lib/<cartridge_name>.jar | Pipelines, see Overview - Pipelets and Pipelines |
/src/main/resources
| /lib/<cartridge_name>.jar | Queries, see Reference - Query File Syntax |
/staticfiles/cartridge/static | /static | Static content like static HTML, images, and scripts (possibly locale-specific) |
/src/main/isml | /lib/<cartridge_name>.jar | ISML templates (possibly locale-specific) |
/src/main/resources
| /lib/<cartridge_name>.jar | WebForms, see Concept - Webforms |
/staticfiles/cartridge/webservices | /webservices | Web Service Deployment Descriptors (wsdd) |
Meta data of a cartridges include the display name, version, build number and the dependency list.
plugins { id "java" id "com.intershop.gradle.cartridge-resourcelist" id 'com.intershop.icm.cartridge.product' } ext.displayName = "Adapter - Customization" dependencies { cartridge "com.intershop.business:bc_mvc" implementation "com.google.guava:guava" }
Versions can be defined at a central place (e.g. in a versions project) with the java-platform plugin.
include("versions")
2. declare versions as constraints. (inject constraints to other projects via code).
The cartridge engine is responsible for loading the meta data of cartridges listed in CARTRIDGE_LIST environment when Application Server is started:
CARTRIDGE_LIST: ft_icm_as
Feature Cartridges
With ICM 11.0 each listed cartridge defines its dependencies (other cartridges and libraries). It is possible to reduce the number to a minimum by introducing feature (ft_) cartridges that depend on the "root" cartridges of your applications. This means if a new cartridge is created and this cartridge is listed in the dependencies of the "root" cartridges, no adaption of the deployment configuration is required.
The Order of Cartridges
In ICM 11.0 the cartridgelist.properties are not longer used. Instead a short list of feature cartridges can be declared (system property is.cartridges) to define the root cartridges of the application server. The dependencies play an important role and are used to determine the order of the cartridges. In case two or more cartridges have the same "level or layer" then the cartridges are listed by name.
During startup and shutdown of the application, cartridges are registered at lifecycle hooks.
A lifecycle class for the cartridge can be defined in the administrative properties (/src/main/resources/cartridges/<cartridge-name>.properties).
The property intershop.cartridges.<cartridge>.classname
is used to define the Java class for the cartridge lifecycle. This class needs to implement com.intershop.beehive.core.capi.cartridge.Cartridge providing appropriate lifecycle methods.
Hook | Available Resources | What can be Done | Notes |
---|---|---|---|
onInitHook | Object graph will be generated | ||
onStartupHook | |||
onPreReadyHook | Server Guice binding and configuration | Registering code to use in "dbprepare"-phase | Available from 11.0, similar to old onDBInitHook() |
onReadyHook | Database with fully preparation | Prefetching, establishing connections | Code onPreReadyHook does not need to be executed again |
onPreShutdownHook | All like during running server | Stop jobs, get "offline" to avoid further requests | |
onShutdownHook | Some resources can be closed and not available anymore | Closing connections, disable event processing |
Life Cycle Hooks 11.0 | Life Cycle Hooks <= 7.10 |
---|---|
Please reduce the functionality inside of the cartridge class. We will remove this mechanism in future releases. Your global instances should be registered and instantiated via Dependency Injections and Object Graphs.
An Intershop application consists of the following architectural layers with corresponding cartridge types:
Cartridges must be named according to the architectural level that they represent:
Layer | Cartridge Type | Description | Typical Contents | Cartridge Naming | Java Package Naming | Example |
---|---|---|---|---|---|---|
Features | Feature Cartridge | Contains only dependencies to requested cartridges
| build.gradle | ft_ | ft_backoffice | |
Configuration Layer | Demo Cartridge | Contains demo data for application, this data is optional | product xml files, images, demo content | demo_* | com.intershop.demo.* | demo_responsive |
Initialization Cartridge | Configures and initializes one or more applications in the database (like initial user accounts, organization structures, preferences etc.), this data is necessary to use the applications | import files, dbinit property files | init_* | com.intershop.init.* | init_operations | |
Application Suite Cartridge | Configures and integrates multiple application types to form a complete business scenario This type of cartridges can only be referenced by ft-cartridges or other as-cartridges when an application type needs to reference others. In former versions, the application types were declared here, please use the "Application Cartridge", which introduces the application type for declaration now. REST APIs must also be declared at application cartridges | app and instance component files | as_* | as_backoffice | ||
Application Layer | Adapter Cartridge | Provides an implementation for a business API, which integrates external systems, like external search engines, and allows to extend existing applications It's not allowed to add an ac_ cartridge to multiple application types using an app-extension.component file in the ac_cartridge. These assignments should be done in an component file of an as_cartridge. | Java code, pipelines, ISML templates | ac_* | com.intershop.adapter.* | ac_payment_paypal |
Application Cartridge | Provides user interfaces for an application type. Provides declaration of application type and cartridge list providers (component files) for this application type. | view pipelines, ISML templates, ... | app_* | com.intershop.application.* | app_sf_webshop_smb | |
User Interface Cartridge | Provides a common user interface library which is used to develop application types based on the same technology | ISML templates, pipelines, JavaScript libraries, stylesheets, web forms, pagelets | ui_* | com.intershop.ui.* | ui_web_library | |
Business Layer | Business Cartridge | Provides a business API and/or an implementation for shared reusable business components | Java code, business objects and extensions, pipelets, EDL models, persistent objects, database scripts, queries | bc_* | com.intershop.component.* | bc_basket |
Platform Layer | Platform Cartridge | Implements shared platform frameworks that are needed across all architectural layers | Java code, EDL models, pipelets | pf_* | com.intershop.beehive.* (deprecated) | pf_objectgraph |
(none) | Business Independent Functionality | Standard gradle, maven project (Single Project) | no prefix | com.intershop.common.* | encryption | |
Development | Development cartridges are introduced to give more insides into the existing data or processing. These cartridges are used for developers only and installed on development environment only. For example explain data structure of basket calculation rule results; extended logging via lillith tool | all | _dev postfix or dev_ prefix |
The different cartridge types have well-defined allowed dependencies with each other. The cartridge type is reflected in the cartridge name.
Cartridge Dependency Rules
The dependencies can also be expressed in a matrix: the rows represent the using layer, the columns represent the used layer:
Cartridge Type | Feature | Development | Initialization | Application Suite | Adapter | Application | User Interface | Business | Platform | Common Library |
---|---|---|---|---|---|---|---|---|---|---|
Feature Cartridge | ||||||||||
Development Cartridge | ||||||||||
Initialization Cartridge | ||||||||||
Application Suite Cartridge | ||||||||||
Adapter Cartridge | ||||||||||
Application Cartridge | ||||||||||
User Interface Cartridge | ||||||||||
Business Cartridge | ||||||||||
Platform Cartridge | ||||||||||
Common Library |
Common libraries must not depend on other common libraries. These components can use open source (MAVEN) available libraries. The platform is responsible for bringing these libraries together.
Adapter cartridges should not depend on other adapter cartridges, only if these are kind of abstract and do not have any references to application cartridges. To register the ac_ cartridge at multiple applications, make usage of as_ cartridges to avoid a dependency to multiple applications.
Application cartridges should only depend on other application cartridges to extend their capabilities. Do not extend (and require) different kind of applications with one application cartridge.
Initialization cartridges are different from normal implementation cartridges because they are usually only used at initialization time of the system (e.g., DBInit). After all content has been prepared and is available in the database/file system, they are no longer needed. The name of an initialization cartridge should reflect the content that is initialized by the cartridge.
Examples:
Cartridges on the same architectural level may form hierarchical structures, where some base functionality that is defined in one cartridge can be refined in additional sub-cartridges. The hierarchy is expressed in the naming of the project.
Example:
The hierarchy in the cartridge name is also reflected in the Java package names of the cartridge. Each additional fragment in the cartridge name is translated to an equivalent level in the Java package name.
Example:
There are cartridges containing integration API tests that test a specific cartridge. The naming of these cartridges should follow the rule: <cartridge>_test, e.g.:
Cartridges in customer projects should follow the same principles as Intershop cartridges.
However, to facilitate differentiation, it is recommended to prefix the cartridge name with an identifier for the vendor, e.g. (customer "XYZ"):
Any cartridge may define an API (for example, using the common CAPI package convention) and / or provide an implementation (that must be located in internal packages, as usual). There may be cartridges that only consist of API and other cartridges that only consist of implementation code, and some cartridges may contain both. There is no special naming for pure API cartridges, as every cartridge is considered to be "equal". If the purpose of an implementation cartridge is to provide the implementation for a certain technology, this should be reflected in the cartridge name.
Example:
Package Examples:
Common package name build pattern for cartridges:
com.intershop.component.product.configuration
.This way you can avoid conflicts with other cartridges if these cartridges use the same pattern and preferred sub-packages (capi, internal, dbinit, pipelet).
When developing a new application, a developer could start on the application layer. It is perfectly okay to put all the implementation code into this application cartridge, including application definitions, templates, pipelines, business objects, persistent objects and so on.
When developing another application, this application could also be completely "self-contained". However, this approach is not very useful, since everything would have to be implemented again and again. Instead, we want to benefit from a maximum reuse of code and existing concepts. Therefore, the common approach is to create "abstractions" or "generalizations" of concepts and move them to the lower architectural layers. This also means that such abstractions must be designed for reuse in multiple different contexts.
Examples: