If we talk about services, we must clearly understand what a service is (in our context). In an end-to-end communication arrangement one communication partner provides certain operations that are bundled in a service; a client calls those operations. The managed part of a service refers to the service framework's capabilities.
For example, a service connection could be established by taking certain objects and arranging (marshaling) them with a created set of call parameters, and sending them via technical connection. You also need to consider logging and monitoring, as well as the addition of structures to assist with call configuration and its assignment to the environment in which you want to run the service. Many of these activities are handled by the "Managed Service Framework".
Services are usually described by interfaces (generally speaking, these can be but not necessarily refer to Java interfaces). That said, we should not assume that every interface is a service.
For a service call situation we assume:
This glossary describes the terms used here ( typewriter style denotes terms that directly correspond with class/interface names):
Term | Description |
|---|---|
Adapter | If you think of a stub/skeleton architecture where the skeleton is the service, then the adapter is the stub that communicates with the service. |
Adapter Interface | A Java interface that is not a marker interface and commonly not a pojo interface. |
Assignment | An assignment is the same as the |
Configuration | Mostly, configuration refers to the term "dynamic configuration". Note Make sure that you do not confuse configuration with |
Dynamic Configuration | The term "dynamic configuration" refers to configurations that have specific parameters. For example, an HTTP request has URLs, timeouts and the like, while a mail sender may have SMTP server, security values, ports and so on. The managed service framework does not limit what parameters a service might support, but it offers easy-to-use parameter definitions to handle those configurations. Since the parameters vary from one to another ServiceDefinition, it is called "dynamic". |
Event | A state change triggers an event. Events in this documentation are lifecycle updates on a |
Hook | A hook is the method that will be triggered by an event. Usually they implement |
Intershop platform | The Intershop server software as distributed. |
New Services | New services are implementations that follow the design described in this document. The designation "new" merely serves to contrast to old services. |
Old Services | Enfinity platform versions from 6.4 have service implementations that follow a distinct design. Those services are supported by the new service framework design, with one major limitation: it is not possible to create more than one |
Service | In an end-to-end communication, one communication partner provides some operations that are bundled in a service, while a client calls those operations. |
|
|
| A |
| A |
| A ServiceDefinition is a stateless object that
|
| The |
| The |
| When registering a |
| A |
| The ServiceProvider is a stateful object (as it may hold a ServiceConfigurationBO reference) that serves an adapter that corresponds to the requested adapter interface. It is served by a |
Service type | Synonym for ServiceDefinition, but focuses more on the business view. |
XSD | XML schema description |
This chapter describes some artifacts in the INTERSHOP platform that constitute the Managed Service Framework.
The following diagram shows - extremely simplified - the parts of the managed service framework.
ServiceDefinition that refers to one or more adapters and supports access to them.ServiceConfigurationBORepository that is the link to the context whereby services are accessed and these may own specific settings for a service.ServiceConfigurationBO that associates a ServiceConfigurationBORepository with the ServiceDefinition. Thus, ServiceConfigurationBORepository specific settings are stored and so the adapters operate ServiceConfigurationBORepository-aware, hence App-aware (if ServiceConfigurationBORepository is an App-Repository).The following chapters will take a closer look at the artifacts specified here and introduce additional artifacts that surround those previously mentioned.
While an adapter is the object that makes the service call possible, still, it is not a part of the Managed Service Framework. The adapter is a component that "knows" how to access the service. In the INTERSHOP platform, an adapter is defined by any Java interface (see the following chapter). There is no restriction on the adapter implementation. Essentially, any object can become a service adapter as long as it implements at least one interface.
The adapter has to take care of:
As mentioned before, any object that implements a Java interface can serve as an adapter.
However, there are some constraints that must be considered: Avoid adapters for marker interfaces and pojos.
Example:
Note
You could think of the Address interface as being an adapter interface. However, this would mean that getting a name or getting a street are service calls. That would not be very useful.
In the INTERSHOP platform, the adapter interface is represented in two shapes:
<T> in the getServiceAdapter(Class<T>) method of the ServiceProvider in bc_service andgetServiceAdapter(Class<T>) method and in the return value of the getServiceInterfaces() method of the ServiceDefinitionAs a programmer you might be required to use an existing service, to implement a new stub or to do both.
After reading this concept and with the Cookbook - Managed Service Framework at hand, you should be able to fulfill your task.
Note
If you are asked to enhance/change the framework itself, do not forget to update this documentation.
Note
Adapter interfaces should be marked as managed service using com.intershop.component.service.capi.service.ManagedService. This marker annotation is used by external tools.
This is how a service is looked up and how it is called ("use an existing service") - using the "Address" example mentioned above:
ServiceConfigurationBORepository serviceConfigurationBORepository = applicationBO.getRepository( "ServiceConfigurationBORepository" );
for (AddressValidator addressValidator : serviceConfigurationBORepository.getServiceAdapters( AddressValidator.class ))
{
addressValidator.validate( address );
}
The ServiceConfigurationBORepository will be discussed later in this document. The AddressValidator is a Java interface that defines a stub for an address validator service. The variable addressValidator contains an adapter implementation. The method validate encapsulates the address validation operation of a validation service. The address parameter is considered an Address object as defined in the example above.
To implement a new stub for a service, follow these proceedings:
To make the new service adapter available in the INTERSHOP platform, some more artifacts have to be established, which will be discussed in the following chapters:
Optionally, these parts may also be needed:
There are abstract adapter classes that provide a lot of functionality that may be needed: SingleOperationAdapter and MultiOperationAdapter. For more details refer to the Cookbook - Managed Service Framework.
A ServiceDefinition is a stateless object that
ServiceConfigurationBO state changes by defining lifecycle hooksSometimes several adapter interfaces can be bundled for functional reasons. Think, for example, of an inventory service. There might be an interface that just retrieves the quantity on stock and another one that manages a reservation lifecycle. Thus, there might be a QuantityRequest interface and a Reservation interface. The two of them could be bundled to one InventoryServiceDefinition that supports both interfaces. The supported interfaces are retrievable by accessing the Collection<Class<?>> getServiceInterfaces() method.
When a service is looked up using the ServiceConfigurationBORepository, the lookup strategy of the framework will ask the ServiceDefinition to serve an appropriate ServiceProvider for a given ServiceConfigurationBO. That means, the ServiceDefinition must analyze the ServiceConfigurationBO and select a suitable ServiceProvider based on it.
The ServiceDefinition might cache instances, connections o.t.l. To remain up-to-date consistently, the ServiceDefinition can implement BusinessObjectListener<ServiceConfigurationBO>.
The ServiceProvider is a stateful object (as it may hold a ServiceConfigurationBO reference) that serves an adapter that corresponds to the requested adapter interface.
Thus, it does not define more than this method:
<T> T getServiceAdapter( Class<T> serviceInterface );
As both ServiceDefinition and ServiceProvider implementations are located in the internal section of a cartridge and the ServiceDefinition provides a ServiceProvider according to a ServiceConfigurationBO, there must be a technique to generically switch the ServiceProvider, if it is intended to be able to add new adapters in new cartridges that support a certain ServiceDefinition. The AbstractServiceDefinition offers capabilities to add adapters from outside the original cartridge.
The ServiceDefinitionRegistry is the central point where ServiceDefinition instances are registered and retrieved. Usually, ServiceDefinition instances are wired to the ServiceDefinitionRegistry using the Component Framework.
The entry of the ServiceDefinitionRegistry contains some more (descriptive) attributes in addition to the ServiceDefinition itself.
There are so-called "old" services (services that have been implemented prior to INTERSHOP 7) and "new" services.
ServiceInformation implementations,ServiceDefinition implementations. The old services will be supported.The ServiceInformation interfaces provide some methods that correspond with some component configuration in the new framework. The ServiceInformationServiceDefinitionBridge is a wrapper around a ServiceInformation and turns it to a ServiceDefinition.
Component configuration key (new) |
| prefix | |
|---|---|---|---|
| does not exist for old services. | constant | A |
| getGroupID() | service.group.name | All whitespace will be replaced by underscores ( |
| getParameterGroupID() | not prefixed | |
| getServiceID() | not prefixed | A |
| does not exist for old services |
| All whitespaces will be replaced by underscores ( |
The ServiceDefinitionRegistry also holds references to so-called "chain elements". These are handlers that are part of the service call chain and may listen to the data exchange stream for, e.g., logging or monitoring reasons.
The following diagram shows the references between the adapter, adapter interface, ServiceProvider, ServiceDefinition, ServiceDefinitionRegistry.Entry and ServiceDefinitionRegistry.
There is an AbstractServiceDefinition that offers lots of implementations and makes it straightforward to have a new ServiceDefinition implementation (incl. a sufficient ServiceProvider). For more details refer to the Cookbook - Managed Service Framework.
The ServiceDefinitionKeyPO represents the link between the "Java world" and the persistent layer. A ServiceDefinition is uniquely referenced by the cartridge id and the service definition id. This is because a programmer just needs to ensure that the ServiceDefinition has a unique service definition id within "his/her" cartridge. Some database objects, like ServicePermissionPO and ServiceConfigurationPO are holding references to that ServiceDefinitionKeyPO. These references are used by the ServiceConfigurationBORepository and ServiceConfigurationBO to be able to lookup "their" ServiceDefinition objects.
A ServiceConfigurationBORepository is a central point to manage the lifecycle of service configurations and it supports access to the adapters. Different ServiceConfigurationBORepository objects are available for different contexts, such as applications (see Concepts - App and Application Framework (until 6.6.x)). So a ServiceConfigurationBO associates a ServiceDefinition with a ServiceConfigurationBORepository. Any artifact that wants to handle services in any way must have a ServiceConfigurationBORepository to do so. When it is intended to use a service, it should be checked first whether there is a ServiceConfigurationBORepository for the context in mind.
The diagram above shows how ServiceConfigurationBORepository, ServiceConfigurationBO and ServiceDefinition correspond with each other.
It illustrates
ServiceConfigurationBORepository can have a ServiceMasterRepository- a kind of parent - that may share its ServiceConfigurationBO objects to the actual ServiceConfigurationBORepositoryServiceConfigurationBORepository can have one or more dependents - a kind of child element - that may get ServiceConfigurationBO objects shared from the actual ServiceConfigurationBORepositoryServiceConfigurationBORepository can own and refer to a ServiceConfigurationBO or just refer to a ServiceConfigurationBOServiceConfigurationBO means that the actual ServiceConfigurationBORepository controls the lifecycle of it, i.e., it creates it. You can say "the ServiceConfigurationBO is located in the ServiceConfigurationBORepository". If a ServiceConfigurationBORepository owns a ServiceConfigurationBO, none of its parents can refer to it (because that would mean there is a circle dependency in the ServiceConfigurationBORepository structure).ServiceConfigurationBO means that it is a shared one from a ServiceMasterRepository. All "children" and "grandchildren" a.s.o. may refer to ServiceConfigurationBO objects. They may also control the activation behavior for themselves.ServiceDefinition can have 0..n ServiceConfigurationBO that refers to it. Thus, several configurations for different use cases can be managed.The ServiceConfigurationBORepository is just a composition of three interfaces that define three aspects of it:
ServiceExecutable that covers methods needed to access a serviceServiceInstantiable that covers methods to configure and to control the lifecycle of a ServiceConfigurationBOServiceMasterRepository that offers methods to access the ServiceConfigurationBORepository hierarchy. This is needed to be able to provide sharing capabilities.Service types can be allowed or prohibited for ServiceConfigurationBORepository instances.
Prohibiting a service type means that
ServiceConfigurationBORepositoryAs discussed above, a ServiceDefinitionKeyPO is the object that connects the ServiceDefinition, which is a pure Java object, with the persistence layer.
From the framework's point of view, all service-related tables can be empty at the beginning. Under normal circumstances they are not, since quite a few services are configured during DBInit.
But since ServicePermissionPO has a mandatory reference to a ServiceDefinitionKeyPO and nothing can be done with services before a ServicePermissionPO is in place, at first a ServiceDefinitionKeyPO must be in place and is created when allowing (or even prohibiting!) a ServiceDefinition.
A ServiceConfigurationBO associates a ServiceConfigurationBORepository with a ServiceDefiniton. It has a name (and localizable display name and descriptions), can be made "accessible" (that will be discussed later on), and it may refer to some specific settings (called "Dynamic Configuration" within this document).
From the persistence layer point of view, the ServiceConfigurationBO is an aggregated object that consists of ServiceConfigurationPO and ServiceAssignmentPO. The ServiceConfigurationPO has attributes and methods that are valid for all artifacts that use the ServiceConfigurationBO object, while a ServiceAssignmentPO contains attributes and values that re-define the activation status of a service configuration. Those values are:
ServiceConfigurationBORepositoryServiceConfigurationBORepository) and if so, whether it should be activated by default or not or whether the usage is even mandatoryThere are different requirements with regard to when a service can be executed from a certain context:
Note
Keep in mind that locally activated can be set explicitly, but also implicitly via the sharing rule of a master repository. That is, if there is no explicit local activation, the master repositories are then looked up. Their sharing rules will control its activation state in that case:
| default activation state for descending repositories |
|---|---|
UNSHARED | not activated |
SHARED_ACTIVATED | activated |
SHARED_DEACTIVATED | not activated |
MANDATORY | activated - overrides locally activated flags |
"Dynamic configurations" are configurations that are not "hard" bound to the ServiceConfigurationBO object, but the ServiceConfigurationBO is rather a key to the appropriate configuration definition and values.
Some services might not need any specific configurations, others do. Configuration parameters will differ widely. Thus, configuration parameter definitions must be configurable.
The usage of ParameterGroup definitions is supported by the managed service framework, but it is not required to do so. There are no methods defined in the ServiceConfigurationBO to access any dynamic configurations.
To access the dynamic configurations, commonly extensions of the ServiceConfigurationBO should be used. There is an ORMServiceConfigurationBOConfigurationExtensionImpl, for example. It implements a ConfigurationProvider interface whose only method is getConfiguration(): Configuration. See Concept - Component Framework (valid to 7.4 CI) to learn more about the Configuration artifacts.
To make a dynamic configuration editable, the ParameterGroup approach should be considered.
The following steps are needed to establish a ParameterGroup together with the ability to edit it in the back office:
ParameterGroup ID when registering a ServiceDefinition.Following this approach there are parameters in the Intershop Commerce Management that must be defined. For detailed instructions, see the Cookbook - Managed Service Framework.
The following diagram is a "big picture" of the discussed artifacts, but shows more detail than in the introduction of this chapter.
From the ServiceExecutable to the adapter interface, there is an imaginary "horizontal line" of artifacts that are obviously used during a service call, and the blue artifact section shows the persistent artifacts. All others are surrounding classes that help to manage the core artifacts.
In the chapter "Adapter Interfaces", it has already been discussed how a service can be called. The following diagram repeats the steps once more:
The red section in the diagram above is worth a closer look:
As mentioned above, there are 4 persistent objects handled by the managed service framework:
Persistent Object | Table name | Extensible/AV |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Without any database initialization none of the services will be available.
Sometimes specific services might be crucial to make the shop work properly, for example services that are used during the checkout. Therefore, these services should be available "out-of-the-box", i.e., after a server installation.
Therefore, 3 preparers are available to initialize a configuration:
ServiceAssignmentPreparerServiceConfigurationPreparerServicePermissionPreparerThere is no specific preparer to add rows to the ServiceDefinitionKey table since an entry is implicitly added "on the fly". That is, a ServicePermission or a ServiceConfiguration has a mandatory foreign key that refers to a ServiceDefinitionKey. When one of them is to be created, the ServiceDefinitionKey is looked up and if it is not already in place, it is created and used.
There is no way to add configuration parameters in DBInit. If that is required, a preparer must be implemented that adds values to the ServiceConfiguration-AV table as long as the type is a "new" type ("old" services use domain preferences for their configuration parameters).
The Cookbook - Managed Service Framework includes a chapter that describes in detail how to use the named preparers.
The monitoring of services is realized with MXBeans and handlers. The ServiceChain handles all registered handlers for a service, including MonitorHandler, LogHandler, and CachingHandler.
If the MonitorHandler is registered, it tracks various data, like successful requests, average answer time, failures etc.
A call works like this:
The RequestStatistics requires 3 parameters, which can be adjusted in the configuration tab of a service:
Long Call Threshold | If an answer of a request takes longer than the number defined in "Long Call", the request is considered a longCall |
Number of Entries | The maximum number of entries, that will be saved in the statistics |
Notification Threshold | Percentage of requests that have to be failures or timeouts for the notfication to be sent |
Depending on those parameters, the statistics can return a status which is either ok (green), with errors (yellow), with exceptions (red), or not used (gray).
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 Website, including, without limitation, any lost profits, business interruption, loss of programs or other data on your information handling system.