Document Properties
KbidU25993
Last Modified15-Mar-2016
Added to KB01-Oct-2014
Public AccessEveryone
StatusOnline
Doc TypeGuidelines, Concepts & Cookbooks
Product
  • ICM 7.6
  • ICM 7.7
  • ICM 7.8
  • ICM 7.9
  • ICM 7.10

Guide - Business Objects

1 Introduction

This guide describes conventions and rules how business objects and supporting infrastructure for the new BO layer must be implemented. The conventions are mandatory, any violations will be treated as bugs. Existing code that does not comply with the conventions must be reworked.

1.1 References

For more information about the concept and an explanation of the used terms in this document, see the related documents:

2 Business Object Cartridges

Depending on the importance of the business object to be implemented, it may be required to create a whole new cartridge. For example, the basket aggregate could be implemented in its own cartridge bc_basket, and the address aggregate could be implemented in the bc_address cartridge, which will also contain all additional things related to the business object, like address validation code and pipelets. Whether or not a new cartridge is needed must be decided from case to case. The recommendation is to create a separate cartridge for every important concept.

It is recommended to separate between the business object API and the (possibly multiple different) business object implementation. Thus we need two kinds of cartridges: API cartridges and implementation cartridges.

2.1 Business Object API Cartridges

A cartridge containing only business object APIs has the name "bc_*". It may contain:

  • business object interfaces
  • business object repository interfaces
  • business object extension interfaces
  • business object pipelets
  • other code like processing pipelines that exclusively operate on the API and are implementation independent

Example:

  • Cartridge: bc_basket

2.2 Business Object Implementation Cartridges

A cartridge containing business object implementations has a name that extends the name of the API cartridge which is implemented by an additional identifier that gives a hint about the underlying implementation technology. For example, cartridges for business objects that are implemented using ORM objects should be called "bc_*_orm".

A cartridge containing business object implementations may contain:

  • business object implementation classes
  • business object repository classes
  • business object extension classes
  • business object extension factory classes
  • other code like persistent ORM beans that are needed by the BO implementation classes.

Example:

  • Cartridge: bc_basket_orm

3 Business Object Repositories

3.1 Business Object Repository Interfaces

The repository is the central entry point for creating or retrieving the root entity (e.g., the root business object) of an aggregate. It hides the underlying implementation.

Rules:

  • Repository interfaces must inherit from com.intershop.beehive.businessobject.capi.BusinessObjectRepository.
  • The name ends with BORepository.
  • There is only one repository per aggregate (not for every business object!).
  • It is named after the aggregate / root entity type, like BasketBORepository.
  • The repository only handles the lifecycle of the root entity type. All dependent objects (e.g., entities) can only be created / retrieved indirectly via the methods of the root entity or other parent entities, but not via the repository.
  • There may be multiple root objects in an aggregate, which can be handled by the same repository.
    • Example: AddressBORepository can handle AddressBO and AddressBookBO, which can both serve as root entities.
  • Use java.util.Collection or similar (List, Set, Map), but do not work with Iterators in the interfaces.
  • The key of an entity is an attribute ID of type String.
  • The repository can provide additional methods for searching objects. However, such methods may not take SQL conditions or similar as arguments, since this makes strong assumptions about the internal implementation.

The methods of the repository contain the name of the business object, including the BO:

  • <BusinessObject> create<BusinessObject>(String id);
  • <BusinessObject> get<BusinessObject>ByID(String id);
  • Collection<<BusinessObject>> getAll<BusinessObject>s();
  • void delete<BusinessObject>(String id);
    • This method simply looks up the BO and invokes its delete-method.

Example:

  • Cartridge: bc_basket
BasketBORepository.java
package com.intershop.component.basket.capi;

import com.intershop.beehive.businessobject.capi.BusinessObjectRepository;

public interface BasketBORepository extends BusinessObjectRepository
{
    public BasketBO createBasketBO(String id);
    public BasketBO getBasketBOByID(String id);
    public Collection<BasketBO> getExpiredBasketBOs();
    public void deleteBasketBO(String id);
}

3.2 Business Object Repository Implementation

The repository implementation implements the repository interface and maps it to an underlying (persistence) technology. There can be multiple alternate implementations for the same repository interface. It may internally rely on other subsystems, like the ORM engine, or can solve everything on its own.

Rules:

  • The repository implementation must implement the repository interface from the API cartridge (which inherits from com.intershop.beehive.businessobject.capi.BusinessObjectRepository)
  • It must be placed in the internal package.
  • The implementation class name should somehow reflect the technology on which the implementation is internally based, like ORM...RepositoryImpl for repositories operating on underlying ORM objects.

Example:

  • Cartridge: bc_basket_orm
ORMBasketBORepositoryImpl.java
package com.intershop.component.basket.orm.internal;

import com.intershop.component.basket.capi.BasketBO;
import com.intershop.component.basket.capi.BasketBORepository;

public class ORMBasketBORepositoryImpl implements BasketBORepository
{
    @Override
    public BasketBO createBasketBO(String id)
    {
        ...//create BO and invokes its objectCreated-method
    }

    @Override
    public BasketBO getBasketBOByID(String id)
    {
        ...
    }

    @Override
    public Collection<BasketBO> getExpiredBasketBOs()
    {
        ...
    }

    @Override
    public void deleteBasketBO(String id)
    {
        ... //look up the BO and invokes its delete-method
    }
}

4 Business Objects

4.1 Business Object Interfaces

The business object interfaces represent the actual business objects. The root entity provides methods for controlling the lifecycle of dependent entities. The entities provide methods for accessing their attributes, for navigation and for processing business operations, resulting in a modification of their structure. All entities completely hide their internal implementation. There may be different backend implementations for them, thus the API may not expose any implementation details. In particular, it may not directly return underlying ORM objects, because this would make an alternative implementation of this BO interface impossible which does not rely on ORM.

Rules:

  • Business object interfaces must extend com.intershop.beehive.businessobject.capi.BusinessObject (directly or indirectly).
  • Public interfaces are put into the normal CAPI package structure.
  • The name ends with BO.
  • The BO methods may not return or take arguments that would leak internal implementation details, like wrapped ORM objects. Returned collections may not contain such objects either.
  • Use java.util.Collection or similar (list, set, map), but do not work with Iterators in the interfaces.
  • Also use BO in the method names that return business objects or collections of business objects.

Example:

  • Cartridge: bc_basket
BasketBO.java
package com.intershop.component.basket.capi;

public interface BasketBO extends BusinessObject
{
    public BasketProductLineItemBO addProduct(ProductRef ref, Quantity amount, Money price);
    public Collection<BasketProductLineItemBO> getProductLineItemBOs();
}

4.2 Business Object Implementations

The business object implementation implements the business object interface and maps it to the internal representation. There can be multiple alternate implementations for the same business object interface.

Rules:

  • The business object implementation must implement the business object interface (and thus indirectly implement com.intershop.beehive.businessobject.capi.BusinessObject).
  • It should (and in most cases: must) inherit from one of the available superclasses. Which superclass must be used depends on the underlying implementation of the BO:
    • Inherit from com.intershop.beehive.core.capi.domain.AbstractExtensibleObjectBO for BO impls that internally use an ExtensibleObject as delegate.
    • Inherit from com.intershop.beehive.core.capi.domain.AbstractPersistentObjectBO for BO impls that internally use a PersistentObject as delegate.
    • Inherit from com.intershop.beehive.businessobject.capi.AbstractBusinessObject for all other BO impls.
  • The implementation classes for business objects, implementing the business object CAPI interfaces, are located in the internal packages of the implementation cartridge.
  • The implementation may provide access to its internally wrapped objects for other business object classes belonging to the same aggregate. However, such methods may not be part of the public CAPI (e.g., the business object interface).
  • The name of the implementation class should reflect the implementation technology (like ORMBasketBOImpl), at least it should be called like BOImpl.

Example:

  • Cartridge: bc_basket_orm
ORMBasketBOImpl.java
package com.intershop.component.basket.orm.internal;

import com.intershop.component.basket.capi.BasketBO;
import com.intershop.component.basket.capi.BasketBORepository;
import com.intershop.beehive.core.capi.domain.AbstractExtensibleObjectBO;

public class ORMBasketBOImpl extends AbstractExtensibleObjectBO implements BasketBO
{
    @Override
    public BasketProductLineItemBO addProduct(ProductRef ref, Quantity amount, Money price)
    {
        ...
    }

    @Override
    public Collection<BasketProductLineItemBO> getProductLineItemBOs()
    {
        ...
    }

   @Override 
   public void delete() {
        super.delete(); //trigger the hooks
        ... //do some clean up (e.g., deletes affected ORM objects)
   }

}

5 Business Object Extensions

Existing business objects can be enhanced in customer projects and / or in other application layers (like the presentation layer) by attaching extensions to them.

5.1 Business Object Extension Interfaces

The conventions for allowed arguments / return values for extensions are not as strict as for business object interfaces, as extensions represent optional features only. There are rarely multiple implementations of the same extension interface.

Rules:

  • The extension interface is placed in the CAPI package.
  • It must inherit from com.intershop.beehive.businessobject.capi.BusinessObjectExtension.
  • The name ends with Extension.
  • It defines a public static final String constant for the EXTENSION_ID. This ID can be used to lookup the extension later, e.g., from an ISML template (using the getExtension method at the BO).
  • Use collections, not iterators.
  • If an extension implements an existing business interface (for example, a business object repository interface), there must still be an additional extension interface which defines the EXTENSION_ID and inherits from both the common BusinessObjectExtension interface and the business interface.

Example:

BasketBOAppliedRebateExtension.java
import com.intershop.beehive.businessobject.capi.BusinessObjectExtension;

/**
 * This extension covers all applied rebate related functionality for the basket
 * business object.
 */
public interface BasketBOAppliedRebateExtension extends BusinessObjectExtension<BasketBO>
{
    /**
     * The ID of the created extensions which can be used to get them from the
     * business object later.
     */
    public static final String EXTENSION_ID = "AppliedRebate";
 
    /**
     * Returns all dynamic messages describing the promotions to gather, when
     * fulfilling the noted condition.
     *
     * @param locale  the locale to return them for
     * @return the collection of dynamic messages
     */
    public Collection<String> getComputedDynamicMessageDiscountItems(Locale locale);
}
RepositoryBOBasketExtension.java
package com.intershop.component.basket.capi;

import com.intershop.beehive.businessobject.capi.BusinessObjectExtension;
import com.intershop.component.repository.capi.RepositoryBO;

/**
 * This extension adapts a RepositoryBO to act as a basket repository.
 */
public interface RepositoryBOBasketExtension extends BusinessObjectExtension<RepositoryBO>, BasketBORepository
{
    /**
     * The ID of the created extensions which can be used to get them from the
     * business object later.
     */
    public static final String EXTENSION_ID = "BasketBORepository";
}

5.2 Naming of Extension IDs

For a logical and consistent naming scheme the EXTENSION_IDs should be named as follows:

Rules:

  • The extension IDs should represent the "business purpose" of the extension. Usually, the part of the class name between BO and Extension is used as EXTENSION_ID, e.g.:
    • MagicBOShippingMethodExtension -> EXTENSION_ID is ShippingMethod
    • MagicBOPaymentExtension -> EXTENSION_ID is Payment
  • In customer projects, a prefix for the customer organization should be added to make a distinction between Intershop extensions and customer extensions:
    • HP_ShippingMethod
    • GSI_ShippingMethod

5.3 Business Object Extension Implementations

For the extension interface, there must be an extension implementation.

Rules:

  • The extension implementations are placed in the internal package.
  • They must inherit from com.intershop.beehive.businessobject.capi.AbstractBusinessObjectExtension and must implement the extension interface.
  • The class name ends with ExtensionImpl.

Example:

BasketBOAppliedRebateExtension.java
import com.intershop.beehive.businessobject.capi.AbstractBusinessObjectExtension;

/**
 * This extension covers all applied rebate related functionality for the basket
 * business object.
 */
public class BasketBOAppliedRebateExtensionImpl extends AbstractBusinessObjectExtension<BasketBO> implements BasketBOAppliedRebateExtension
{
    ...
}

5.4 Business Object Extension Factories

Extension factories are responsible to create instances of business object extension implementation classes.

Rules:

  • They are located in internal packages.
  • They must implement the interface com.intershop.beehive.businessobject.capi.BusinessObjectExtensionFactory.
    For convenience, they can inherit from com.intershop.beehive.businessobject.capi.AbstractBusinessObjectExtensionFactory instead, which already implements some of the required interface methods.
  • The name ends with ExtensionFactory.

Example:

BasketBOAppliedRebateExtensionFactory.java
import com.intershop.beehive.businessobject.capi.AbstractBusinessObjectExtensionFactory;

/**
 * Factory for the specific implementation of the applied rebate extension for the basket
 * business object.
 */
public class BasketBOAppliedRebateExtensionFactory extends AbstractBusinessObjectExtensionFactory<BasketBO>
{
    @Override
    public BusinessObjectExtension<BasketBO> createExtension(BasketBO object)
    {         
        return new BasketBOAppliedRebateExtensionImpl(BasketBOAppliedRebateExtension.EXTENSION_ID, object);
    }
 
    @Override
    public Class<BasketBO> getExtendedType()
    {
        return BasketBO.class;
    }   
 
    @Override
    public Class<BasketBOAppliedRebateExtension> getExtensionType()
    {
        return BasketBOAppliedRebateExtension.class;
    }   
}

6 Business Object Pipelets

Pipelets are the main building blocks for setting up business processes. Therefore, it is essential to use a consistent naming scheme for pipelets that allows customers as well as developers to guess the purpose of a pipelet based on its name only.

The naming convention outlined here is by no means complete. There will always be pipelets that do not fall into the categories defined here. The focus of the naming scheme is to provide guidance for the famous 80% of all cases.

6.1 Create<BusinessObject>

Creates a new instance of the business object in business object repository based on some sort of identification criteria (semantic key) retrieved from the pipeline dictionary. This pipelet should focus on object creation with the primary key attributes and other mandatory attributes. The pipelet should not take care of completely configuring the business object with all optional parameters. This should be done by a following update pipelet.

Dictionary In: Business Object Repository, Semantic Key Attributes
Dictionary Out: Business Object
Error Exit: Yes, if product can not be created
Transaction Mode: Required
Example: CreateProductBO

6.2 Delete<BusinessObject>

Deletes a business object instance from the business object repository. The business object to be deleted should be retrieved directly from the pipeline dictionary. Remove pipelets should not contain any lookup logic for looking up the objects to be removed. Remove pipelets remove a single business object instance only (no iterators).

Dictionary In: Business Object
Error Exit: No, errors that might come up when deleting the object should be gracefully ignored
Transaction Mode: Required
Example: DeleteProductBO

6.3 Update<BusinessObject>

Udates a business object instance (available in the pipeline dictionary) with some new attributes (available in the pipeline dictionary). This pipelet should not have an error connector and should gracefully ignore errors that might come up when updating the object attributes.

Dictionary In: Business Object, Attribute(s)
Error Exit: No, errors that might come up when updating the object attributes should be gracefully ignored
Transaction Mode: Required
Example: UpdateProductBO

6.4 Get<BusinessObject>ByID

Tries to identify a single business object instance within the business object repository based on its semantic key.

Dictionary In: Business Object Repository, Semantic Key
Dictionary Out: Business Object
Error Exit: Yes, if the requested business object could not be found
Transaction Mode: Optional
Example: GetProductBOByID

6.5 Get<BusinessObject>By<Attr>

Tries to identify a single business object instance based on some attribute(s) (not the semantic key). The identifying attribute(s) are retrieved from the pipeline dictionary.

Dictionary In: Business Object Repository, Attribute(s)
Dictionary Out: Business Object
Error Exit: Yes, if the requested business object could not be found
Transaction Mode: Optional
Example: GetProductBOBySKU

6.6 Get<BusinessObject>By<Object>

Same concept as the pipelet above. The only difference is that here another, usually associated, business object is used for the lookup.

Dictionary In: Business Object Repository, (Business) Object
Dictionary Out: Business Object
Error Exit: Yes, if the requested business object could not be found
Transaction Mode: Optional
Example: GetCatalogBOByCatalogCategoryBO

6.7 Get<BusinessObject>sBy<Attr>

Tries to identify a collection of business objects based on some attribute (that is not the semantic key). The identifying attribute(s) are retrieved from the pipeline dictionary. This pipelet is important whenever list of business objects need to be processed (e.g., all departments of an organization).

Dictionary In: Business Object Repository, Attribute(s)
Dictionary Out: Collection <Business Object>
Error Exit: No, instead an empty collection is stored in the pipeline dictionary in case of errors or empty result sets
Transaction Mode: Optional
Example: GetProductBOsBySKU

6.8 Get<BusinessObject>sBy<Object>

Same concept as the pipelet above. The only difference is that here another, usually associated, business object is used for the lookup.

Dictionary In: Business Object Repository, (Business) Object
Dictionary Out: Collection <Business Object>
Error Exit: No, instead an empty collection is stored in the pipeline dictionary in case of errors or empty result sets
Transaction Mode: Optional

Disclaimer

The information provided in the Knowledge Base may not be applicable to all systems and situations. Intershop Communications will not be liable to any party for any direct or indirect damages resulting from the use of the Customer Support section of the Intershop Corporate Web site, including, without limitation, any lost profits, business interruption, loss of programs or other data on your information handling system.

Customer Support
Knowledge Base
Product Resources
Support Tickets