com.pivotal.gemfirexd.internal.shared.package.html Maven / Gradle / Ivy
This package and its sub-packages provides functionality that is
shared between top-level Derby jar files.
NOTE - at this time, this code is not yet shared, but is used solely
by gemfirexd-client.jar. The code placed here was to enable internationalization
of the client. It is put under the shared package because we expect
a framework to be put into place soon that will allow sharing across
jar files.
List of Available Shared Components
Shared code is provided through one or more shared components.
This section lists each shared component, providing essential information for
the consumers of these components.
When you create a shared component, you need to add a section here to describe
it for your consumers.
NOTE: Introducing a new shared component requires a vote with
consensus approval. Adding a new package within an existing shared component
requires a vote with lazy consensus. This is to help ensure that
what we are sharing makes sense and does not accidentally paint us into
some kind of architectural corner. Adding new classes or methods to an
existing shared package does not need to be put up for a vote but should be
reviewed using the standard patch review mechanism.
Common
Description:
This shared component is for code that is (or could be) used across all
Derby jar files. This is a good place for utility routines and services
such as logging/tracing, internationalization, error handling, etc.
Packages:
The Common shared component contains the following packages, all under
com.pivotal.gemfirexd.internal.shared
- common.error - utility code for error and exception handling
- common.i18n - utility code for internationlization
- common.reference - contains classes with shared constants
- common.info - utility code that provides runtime information
Consumers
The only jar file currently using (and thus including) the packages in this
component is gemfirexd-client.jar but it is intended to be used by other jar
files once we have a working shared component infrastructure in place.
Terms and Definitions
Shared Component
A shared component is a collection of one or more packages under
com.pivotal.gemfirexd.internal.shared
that is used by code in more than one
Derby jar file (for example, between gemfirexd-client.jar and gemfirexd.jar, or between
gemfirexd.jar and gemfirexd-tools.jar).
There need only be one shared component
in the system (e.g. the shared package and all its subpackages), but in some
cases it may be desirable or necessary to split out some of these packages into
a separate shared component. For example, if there are packages that only need
to be shared between the network client and the network server, there is no need
to put these classes into gemfirexd.jar, and thus these should probably be
pulled out as a separate shared component.
Backward Compatibility
A consumer built against version X of a shared component should
work with version X' of a module where X' > X. This is called
backward compatibility.
Forward Compatibility
A consumer built against version X of a shared component should
work with version X' of a module where X' < X. This is called
forward compatibility.
Mixed Version Environment
If it is possible for two or more versions of Derby to be available to
the same classloader, this is called a mixed version environment.
It is a requirement that Derby continue to function correctly even in a
mixed version environment. In particular, a Derby class that consumes
a shared component must continue to run without failure, regardless of
the ordering of the search path of the classloader or any other factors.
Any shared code infrastructure that we implement must meet this
requirement.
Issues with Compatibility
Using backward and forward compatibility can allow Derby to run
fairly well in a mixed version environment. However, there
are a couple of significant issues with this approach.
First of all, maintaining compatibility, particularly forward compatibility,
places a huge burden of responsibility on Derby engineers, and can also
create some ugly code. Basically, for forward compatibility, you are required
to check to see if any new feature exists in the current runtime environment
before actually using that feature. This can get pretty ugly.
Maintaining backward and forward compatibility also does
not solve the issue of
shadowing. Shadowing occurs when a particular application is upgraded
to use the new behavior of an existing
shared component, but this behavior is not available because it is shadowed by
an older version of the component.
For example, say Application A and Application B are both deployed in the
same application container. The jar files for A (including Derby jars) are
placed in directory A and the jar files for B (including Derby jars) are
placed in directory B. In this container environment, the jars for A are
loaded before the jars for B.
B is running at version 10.4 of Derby and A is running at 10.3. The Derby
code for B depends upon functionality provided in a new shared package that
does not exist in version 10.3. B then upgrades to 10.4.1 to get a bug fix,
and are quite happy. Then A upgrades to 10.4.0, which includes the new
shared package. The shared package in A shadows the shared package in B,
and all of a sudden B's bugfix disappears and regresses.
For these reasons, we need another approach that guarantees that the
correct version of a shared class
is loaded for each consumer. We need to guarantee that Application B
use 10.3 shared classes, and Application C uses 10.4 shared classes.
This can be solved in one of two ways. Which approach we use has yet to
be decided.
- Derby classloader - in this approach a specialized classloader is
written that loads only from the correct jar file. This approach is
currently under investigation and implementation by David Van Couvering.
- Code copying - in this approach, at build time every shared class
copied and given a different package name for each jar file that uses it.
For example,
com.pivotal.gemfirexd.internal.shared.common.i18n.MessageUtil
would be
copied as
com.pivotal.gemfirexd.internal.shared.engine.common.i18n.MessageUtil
for use by gemfirexd.jar and as
com.pivotal.gemfirexd.internal.shared.client.common.i18n.MessageUtil
for use by gemfirexd-client.jar. In this way there is no chance of clashing
or shadowing in a mixed version environment.
The problem with this approach is that developers must use discipline
to modify the original source file and not the generated
version. For this reason, this approach will only be used if the
classloader approach ends up being unfeasible.
Note that these solutions do not allow complete flexibility
in terms of mixed version environments. In particular, the application
programmer or runtime administrator can not run two different versions of
the embedded driver within the same classloader. As a matter of fact,
that exact configuration is currently not allowed. The proposed solutions
only guarantee that if you do have a mixed version environment
(even by accident), nothing strange or unexpected will happen. It also
allows the network driver to run at
a different version from the embedded driver within the same classloader.
Location
and Distribution of Shared Components
All shared components should comprise of one or more packages
under the package com.pivotal.gemfirexd.internal.shared
(stored in the source tree under
java/common/com/pivotal/gemfirexd/internal/shared
).
Although it would be conceptually nice to have a separate JAR file
for each shared component, it is a priority for us to keep a very
simple user experience. For this reason, the classes of a shared
components will be merged into the appropriate subset of the existing
jar files.
User Visible
Impact and Restrictions
The intent is that the shared component infrastructure and code will have
minimal to no visible impact to users.