In theory, coding your application to the JEE specification makes it portable across different implementations. In practice, it most definitely is NOT a seamless transition from one application server to another.
Why is this? Here are some reasons:
- Gaps in the specification: Certain behaviours or assumptions are not explicitly defined in the JEE specification. JEE implementations will then interpret and define these behaviours and assumptions differently from each other.
- Configuration is outside the scope of the specification: Configuration of application resources (e.g JMS queues/topics, Datasources, etc.) is the outside the scope of the specification, and will be completely different between application servers.
- Unintentional coding to vendor implementation: Even though there may have been a conscious effort to code the application to the JEE specification, it is likely that a few areas of the application were coded to vendor-specific behaviours as "spec behaviour" and "vendor behaviour" cannot be differentiated on only one platform
- Intentional coding to vendor implementation: Vendors supplement the JEE specification with advanced features and components that are beneficial for applications. An application may have required usage of vendor-specific features to fulfill its requirements.
Therefore, supporting multiple application servers is not as straightforward as one may think. However, there are strategies that can be employed to make it easier for your application to be portable across application servers:
- Create a common set of configuration data that represents the resources to be deployed on the application server. Then create a technical process that can map the data into the format required for each supported application server. The mapping procedure can then be integrated into an automated build process.
- Try to avoid using vendor-specific features.
- For the parts of the application that must rely on vendor-specific features, use the Delegator or Adapter software pattern to create a common component that can delegate calls to custom adapters that interact with vendor-specific features.