Announcement: You can find the guides for Commerce 7.5 and later on the new Elastic Path Documentation site. The Developer Center continues to support Commerce 6.13.0 through 7.4.1.Visit new site

Extension Core Module Structure

Extension Core Module Structure

The extensions/core/ext-core module is used to customize and extend core functionality.

It can include extensions to classes in ep-core as well as modules that ep-core depends on, such as ep-settings or ep-persistence-openjpa. It can also include new functionality that needs to be available to other extension modules.

The ext-core module has the following structure:

ext-core
   src  
      main
         java
            com
               java 
                   // Extension classes go here
                resources
                   META-INF
                      conf 
                         ep-core-plugin.xml   // Spring definitions and overrides 
                      jpa-persistence.xml     // OpenJPA persistence additions and overrides                   
                   OSGI-INF 
                      blueprint 
                         springCtx-import.xml // OSGi blueprint descriptor file
   pom.xml 

OSGi configuration

Cortex runs in an OSGi container. This means any library Cortex uses must be packaged as an OSGi bundle. This section describes how ext-core is configured for OSGi.

Extension pom.xml

The key OSGi configuration is highlighted in this snippet from the core extension's pom.xml.

<artifactId>ext-core</artifactId>
<packaging>bundle</packaging>
 ...
<build>
   <plugins>
      <plugin>
          <groupId>org.apache.felix</groupId>
          <artifactId>maven-bundle-plugin</artifactId>
          <extensions>true</extensions>
          <configuration>
             <instructions>
                <!-- Fragment-Host gives the symbolic name of the core wrapper bundle to attach to. -->
                <Fragment-Host>ext-commerce-engine-wrapper</Fragment-Host>
                <Import-Package>
                   !*
                </Import-Package>
                ...
             </instructions>
          </configuration>
      </plugin>
      ...

The first OSGi configuration data in the POM is the project's packaging: <packaging>bundle</packaging>. This tells Maven to build the project as an OSGi bundle. The project still builds into a JAR file, so the project can be used outside of an OSGi setting, which means you can leave this as is even if you are not using the core extension in an OSGi setting.

The maven-bundle-plugin configuration turns the core extension into a OSGi fragment and tells the fragment to attach to Cortex's ext-commerce-engine-wrapper bundle. The extension commerce engine wrapper bundle wraps the core extension in an OSGi bundle. Fragments are treated as part of the host bundles. Relevant definitions of the fragment are merged with the host bundle's definitions before the host is resolved, as long as the information does not conflict. Fragment dependencies are resolved if possible. If the fragment dependencies cannot be resolved, the fragment does not attach to the host bundle. A fragment cannot have its own class loader or bundle activator. It cannot override the information present in the host bundles. Fragments extend bundles with resources, classes, and permitted headers enabling you to customize your bundles.

The <Import-Package> element contributes any additional imports to the core bundle. The core bundle already has everything we need, so we are telling it to not import anything by specifying !* If your core extension relies on additional third party libraries (other than those already used by core), you must list the required packages in the <Import-Package> instruction. If you do this, include the manifest header directive value identifying a mandatory resolution type to enable attachment problem logging. For example:

<Import-Package>
  org.thirdparty.library.package; resolution:=mandatory,
  !*
</Import-Package>

If you don't specify the mandatory resolution, OSGI won't find your third party library package at run time and the fragment will fail to attach, but no error message will appear.

springCtx-import.xml

This file tells OSGi where to find the spring configuration for the extension project.

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" >

    <!-- Let OSGI know the spring configuration of this project. -->
    <import resource="../../META-INF/conf/ep-core-plugin.xml" />
</beans>

Notes

  • Core extension classes replacing the out-of-the-box core classes (meaning classes that have the exact same package structure and class name) will not work with this approach.
  • If the extension uses third-party libraries, additional configuration is required:
    • Add the third-party packages to the <Import-Package> element (as described above in Extension pom.xml)
    • If the third-party libraries are OSGi compliant, add them as a dependency and artifact item in the Cortex Webapp.
    • If the libraries are not OSGi compliant, they need to be embedded in the fragment.

jpa-persistence.xml

The core extension's jpa-persistence.xml file specifies the following:

<persistence-unit name="commerce-persistence-unit">
   ...
   <mapping-file>...</mapping-file>

   <class>...</class>

   <exclude-unlisted-classes>true</exclude-unlisted-classes>

   <validation-mode>NONE</validation-mode>

   <properties>
      <property name="openjpa.Log" value="slf4j"/>
      <property name="openjpa.DetachState" value="loaded(DetachedStateField=true)"/>
   </properties>

</persistence-unit>
  • <mapping-file> - Defines the classpath for new ORM metadata mapping files.
  • <class> - Defines the fully qualified class names of the new persistent classes.
  • <exclude-unlisted-classes> - Must be set to true so that OpenJPA will scan only the classpaths of the listed classes. OSGI does not permit scanning of unlisted clases.
  • <validation-mode> - Must be set to NONE, so that OpenJPA does not automatically perform JSR 330 validation on objects persisted to the database.
  • <properties> - Must have values as shown above. openjpa.DetachState is used during OpenJPA bytecode enhancement.
    Important: Do not add additional properties here. To add or override OpenJPA properties, see Override Persistence Unit Properties.

For more information about how to exclude existing ORM mapping files and/or persistent classes, see Exclude references from the Persistence Unit.