Mail Archive Home | architecture List | June 2004 Index
Fractal packaging specification
- Subject: Fractal packaging specification
- From: Eric Bruneton <Eric.Bruneton@xxxxxxxxxxxxxxxxxxxx>
- Date: Wed, 2 Jun 2004 17:55:58 +0200
here is a draft specification for Fractal packaging, which follows
from the discussions on the Fractal mailing list. Comments are
welcome, as well as ideas for source packages, legacy packages,
version management...
Eric
PS:
- nothing is said about "modules" here since this is not related to
packaging itself (see
http://www.objectweb.org/wws/arc/fractal/2004-04/msg00066.html)
- during a meeting betwen FTR&D and SARDES, the following issues were
raised:
- what about =, <, >, >=, ... for version numbers? what about
"excludes", "conflicts", ... clauses based on version numbers?
- Linux shared libraries have their own version numbers, in addition
to the rpm or debian package version numbers. Is this really
necessary, or does this just come from historical reasons? In other
words, do we have all the necessary version information? are we
mixing several distinct concepts?
Title: Fractal Packaging Specification
Fractal Packaging Specification
date:
|
June 2, 2004
|
version:
|
0.1
|
status:
|
draft
|
1 Introduction
This document defines a packaging system for Fractal components. The
main principle is that a Fractal package is a Fractal component in a
serialized form. All the properties of Fractal packages are then
deduced from this identity relation.
Notes:
- in the rest of this document, the "package" term always refer to
Fractal packages. Java packages, which have nothing to do with Fractal
ones, are referred to as "Java packages".
- this version of the specification does not consider source
packages nor legacy components (this is left to future versions).
2 Generalities
Definition: a Fractal package A.far is a Fractal component A in a serialized form, which
is described by a Fractal ADL definition A.fractal contained in the
package itself.
This definition unifies the package and component concepts, in the
sense that a package is just a special form of a component. All the
properties of Fractal packages are then deduced from this identity
relation, as shown in the rest of this section.
2.1 Package containment
A Fractal component A can
contain sub components, which can contain sub sub components, and so on
recursively. A package A
must then be able to contain the serialized form of A, of its sub components, of
its sub sub components, and so on recursively.
A composite component can be distributed on several hosts or address
spaces, by distributing its direct or indirect sub components on
several hosts or address spaces. By analogy, it must be possible to
split the serialized form a component into several package files.
A composite component can expose or not its internal components to the
external components. A package must therefore be able to expose or not
its internal packages to the external packages.
In order to ensure the above properties, the above definition is
completed by saying that:
- a package A.far can contain, in addition to the ADL
definition and the files describing A itself (which are mandatory),
the ADL definitions and the files describing some or all of the direct
or indirect sub components of A.
- a package A.far cannot contain the ADL definition
or the files describing a component B if B is not a direct sub component
of one of the components included in A.far or, more generally, if B is not referenced by an ADL
definition included in A.far.
- the only externally visible component of a package A.far is the component A itself: its direct or
indirect sub components are not visible, unless they are put in
separate .far files.
Example 1: the package A.far below contains the
definition of its direct sub component B, but does not contain the
definition of its sub sub component C, which is defined in a
separate C.far package.
Unlike C, the name "B"
cannot be known from the outside world, and its definition is hidden.
package A.far
A.fractal:
<definition name="A">
<interface name="i" role="client" signature="I"/>
<component name="b"
definition="B"/>
...
</definition>
B.fractal:
<definition name="B">
<component name="c"
definition="C"/>
...
</definition>
... other, non ADL files ...
package C.far
C.fractal:
<definition name="C">
...
</definition>
... other, non ADL files ...
|
2.2 Package dependencies
The dependencies between Fractal components can only be
of two sorts: dependencies through component encapsulation, and
dependencies through component interfaces. These two dependency types
give two dependency types between Fractal packages:
- a containment dependency gives a strong dependency between two
packages
(in the above example, the containement of c inside b, gives a strong
dependency between package A
and package C).
- a dependency through interfaces gives a loose dependency
between packages (in the above example, the mandatory client interface i gives a loose dependency
between package A and any
package that
provides the I interface;
an optional client interface gives optional
package dependencies).
Note: the inheritance relation
in the Fractal ADL gives another dependency type between packages,
which does not have an equivalent for component instances.
2.3 Package versions
Currently there is no versioning system for Fractal components, but
nothing prevents us to define one. This is what is done here, for
components and packages. Versions are indeed especially important for
packages, which are long lived entities (while components, being
runtime entities, can be very short lived).
In order to represent implementation and interface versions, and in
order to constrain the two dependency types with versions, versions are
needed both for components and interfaces. We therefore introduce
versions for component interface types (more precisely for interface
signatures) and for component types and templates (component instance
versions are not needed).
Example 2: the example below is
the same as Example 1, with version numbers for component and interface
definitions. The version of a package is the version of the top level
component it contains.
package A-1.0.far
A.fractal:
<definition name="A" version="1.0">
<interface name="i" role="client" signature="I" version="1.1"/>
<component name="b" definition="B-1.1"/>
...
</definition>
B.fractal:
<definition name="B" version="1.1">
<component name="c" definition="C-2.0"/>
...
</definition>
... other, non
ADL files ...
package C-2.0.far
C.fractal:
<definition name="C" version="2.0">
...
</definition>
... other, non
ADL files ...
|
Notes:
- a component version is an implementation version and, as such,
applies to all the implementation details of the component, including
its interfaces, and its direct and indirect sub components. For
example, if the version of the i
interface or of the b sub
component is changed in A,
then the version of A
must be changed also.
- an interface signature I
may contain references to another interface signature J. Theoritically, if a method
is added or changed in J, the version of I must change, even if I
itself has not changed, since the change in J impacts the contract
defined by I. This feature is not required here.
3 Fractal ADL modules for packaging
Two new ADL modules are defined here: one to be able to define the
content of a package, and one to be able to define versions (the second
one is independent of packaging issues, i.e. it can be used without a
packaging system, and the packaging system can be used without
versions; it is however defined here for practical reasons).
3.1 Content module
This module defines two new AST interfaces and extends the definition and component AST nodes in order to
be able to define the list of files that make up a component:
package org.objectweb.fractal.jar.adl;
public interface
File {
String getName ();
void setName (String name);
}
public interface FileContainer {
File[] getFiles();
void addFile (File f);
void removeFile (File f);
}
<?add
ast="file"
itf="org.objectweb.fractal.jar.adl.File" ?>
<?add ast="definition"
itf="org.objectweb.fractal.jar.adl.FileContainer" ?>
<?add ast="component"
itf="org.objectweb.fractal.jar.adl.FileContainer" ?>
Each file node defines
exactly one file by giving its full name, relatively to some directory
(* and other wildcards are not allowed).
The
list of files of a component must include all the files for the
interfaces and for the implementation of the component itself, without
taking into account its direct or indirect sub components. This list
defines all the files that must be included in a package for this
component.
Note that, thanks to the generic inheritance mechanism of the Fractal
ADL, the files defined in a definition are automatically inherited in
its sub definitions.
Example 3: a component type definition typically contains the
list of files that define the client and server interface signatures,
so that any sub definition automatically include these files.
<definition name="AType">
<interface
name="i" role="client" signature="I"/>
<file
name="I.class"/>
</definition>
<definition name="AImpl"
extends="AType">
<content
class="AImpl"/>
<file
name="AImpl.class"/>
<file
name="C.class"/>
</definition> |
3.2 Version module
This module defines two new AST interfaces and extends the definition and interface AST nodes in order to
be able to define component and interface versions:
package
org.objectweb.fractal.jar.adl;
import
org.objectweb.fractal.adl.Definition;
import
org.objectweb.fractal.adl.interfaces.Interface;
public interface
VersionDefinition extends Definition {
String getVersion ();
void setVersion (String
version);
}
public interface VersionInterface
extends Interface {
String getVersion ();
void setVersion (String
version);
}
<?add ast="definition"
itf="org.objectweb.fractal.jar.adl.VersionDefinition" ?>
<?add ast="interface"
itf="org.objectweb.fractal.jar.adl.VersionInterface" ?>
In order to reference a given version of an existing definition, one
must give its name, followed by '-', followed by its version. Example 2
illustrates how this module can be used.
4 Package file format
In order to exchange packages between package repositories (see next
section), a standard format is needed. This section defines such a
format.
A Fractal package A.far
is jar file with the following constraints:
- the MANIFEST file
must contain a Component-Name
attribute whose value must be the name and version of the top level
component contained in the package.
- the jar file must contain the Fractal ADL definition of this top
level component.
- each file listed in an ADL definition which has a version must be
put in a directory whose name is equal to this version (and the ADL
definition itself must also be put in this directory).
Example 4: the package below
defines the ServerImpl
component in version 1.1, which implements the ServerType version 1.0. The I class is put in the 1.0 directory, since it is
declared in a definition whose version is "1.0". For the same reason,
the ServerImpl and the C classes are put in the 1.1 directory. Note that the ServerType definition and the I class could have been put in
a separate package.
META-INF/MANIFEST.MF:
Manifest-Version: 1.0
Component-Name: pkg.lib.ServerImpl-1.1
1.0/pkg/api/ServerType.fractal:
<definition name="pkg.api.ServerType" version="1.0">
<interface name="i" role="server"
signature="pkg.api.I"/>
<file name="pkg/api/I.class"/>
</definition>
1.0/pkg/api/I.class:
...
1.1/pkg/lib/ServerImpl.fractal:
<definition name=pkg.lib.ServerImpl"
extends="pkg.api.ServerType" version="1.1">
<content class="pkg.lib.ServerImpl"/>
<file name="pkg/lib/ServerImpl.class"/>
<file name="pkg/lib/C.class"/>
</definition>
1.1/pkg/lib/ServerImpl.class:
...
1.1/pkg/lib/C.class:
...
|
Notes:
- it is recommended to name a Fractal package containing the
version 1.1 of the component foo.bar.C
foo.bar.C-1.1.far.
- we considered the possibility to include a .far file inside another .far file, and so on
recursively, in order to have "fractal" packages. We rejected it
because it does not bring any advantages, compared to a "flat" format.
- in the case of Java, and due to the presence of version
directories, a package cannot be used directly as a normal jar file
with standard class loaders.
5 Package repositories
A package repository is a storage that contains Fractal packages. Many
implementations are possible, including remote and local
implementations, implementations based on a file system, on a database,
using JDBC, JDO... This section only specifies the APIs that a package
repository must implement:
package
org.objectweb.fractal.jar.api;
interface PackageSource {
Iterator<String>
getPackageNames ();
Package getPackage (String
name);
Iterator<String>
getPackageDependencies (String pkg);
Iterator<String>
getDependentPackages (String pkg);
Iterator<String>
findPackages (String itf);
}
interface PackageRepository
extends PackageSource {
void addPackage (byte[]
pkg);
void addPackage (String
name, PackageSource src);
void removePackage (String
name);
}
interface Package {
String getName ();
Iterator<String>
getFileNames ();
byte[] getContent ();
byte[] getFile (String
name);
}
A PackageSource is an
immutable package repository. It provides operations to get the names
of the packages in the repository, to get a given package, to get the
direct (strong and loose) dependencies of a package (as a list of
package names), to get the packages that (strongly or loosely) directly
depends on a given package (again as a list of package names), and to
find the packages that provide a given interface (this operation can be
implemented on top of the other methods, but doing so could be very
inefficient, in particular with remote package sources; this is why
this non primitive method is included in this interface).
A PackageRepository is a
mutable package source. It provides operations to add and remove
packages from the repository (note that a new package can be added
either from scratch or from an existing repository).
The Package interface
represents a package, and gives read only access to its name, to the
names of the files it contains, to the content of the package in far
file format, and to the content of each individual file it contains.
A package source or a package repository R must always be self
contained, i.e. for each (strong or loose) dependency of each package
in R, the (or a) package satisfying this dependency must be available
in R. The add and remove operations must preserve this property. As a
consequence:
- the add(byte[])
operation can only be used for a package without dependencies, or whose
dependencies are already satisfied by the packages already available in
the repository.
- the add(String,
PackageSource) operation must retreive from the given source
the package whose name is given, as well as all the packages that are
necessary to satisfy its dependencies, and so on recursively. Note that
all these packages can be retrieved from the given source, since, by
hypothesis, it must itself be self contained.
- the remove
operation must remove not only the package whose name is given, but
also all the packages that depends on this package, and so on
recursively.
Several packages can contain the same version of the same file. For
example, the packages for a client component and for a server component
both contain the file that defines the signature of the interface used
by these components to communicate. A package source or a package
repository must therefore ensure that all the definitions of a given
file are equal in all the packages that contain this file.
Notes:
- in the above interfaces, the package, interface and file names
given as
argument or returned as result are supposed to include a name and an
optional version, separated by '-'.
- in the above interfaces, all the iterators provide read only
access, i.e. their remove
method does nothing.
- there is no need for a separate interface to allow users to
choose one component when several components can satisfy a loose
dependency: indeed the PackageSource
interface can be used for that, if it is implemented as a proxy to an
existing package source, and with a find method based on policies
or interactive user feedback.
- the above API can be used by graphical or web based tools to
manage
package repositories, as well as by "loader" components in order to
instantiate an application from one or more packages.
- the getPackageDependencies
and getDependentPackages
operations are not defined in the Package
interface because they do not have an absolute meaning, unlike the
methods of the Package
interface: indeed the result of these methods depends on the other
packages that are available in the repository.
- Fractal packaging specification,
Eric Bruneton
Powered by MHonArc.
Copyright © 1999-2005, ObjectWeb Consortium | contact | webmaster.