2011/08/05 - Jakarta Cactus has been retired.

For more information, please explore the Attic.

Cactus API design rules

Most of these rules are extracted from the excellent How to Use the Eclipse API article by Jim des Rivieres.

Public APIs/SPIs

To try to draw the line more starkly, the code base for the platform is separated into API/SPI and non-API/non-SPI packages, with all API/SPI elements being declared in designated API/SPI packages.

  • API/SPI package: a Java package that contains at least one API/SPI class or API/SPI interface. The names of API/SPI packages are advertised in the documentation for that component; where feasible, all other packages containing only implementation details have "internal" in the package name. The names of API/SPI packages may legitimately appear in client code. For the Cactus project, these are:
  •   org.apache.cactus.foo.*          - API
      org.apache.cactus.spi.foo.*      - SPI
      org.apache.cactus.internal.foo.* - not API; internal implementation packages 
      org.apache.cactus.sample.*       - not API; these are examples
    
  • API/SPI class or interface: a public class or interface in an API package, or a public or protected class or interface member declared in, or inherited by, some other API class or interface. The names of API classes and interfaces may legitimately appear in client code.
  • API/SPI method or constructor: a public or protected method or constructor either declared in, or inherited by, an API/SPI class or interface. The names of API/SPI methods may legitimately appear in client code.
  • API/SPI field: a public or protected field either declared in, or inherited by, an API/SPI class or interface. The names of API/SPI fields may legitimately appear in client code.
Everything else is considered internal implementation detail and off limits to all clients. Legitimate client code must never reference the names of non-API/non-SPI elements (not even using Java reflection). In some cases, the Java language's name accessibility rules are used to disallow illegal references. However, there are many cases where this is simply not possible. Observing this one simple rule avoids the problem completely:
  • Stick to officially documented APIs/SPIs. Only reference packages that are documented in the published API/SPI Javadoc for the component. Never reference a package belonging to another component that has "internal" in its name --- these are never API/SPI. Never reference a package for which there is no published API/SPI Javadoc --- these are not API/SPI either.

No public methods in internal packages

In order to preserve binary compatibility, no user public API/SPI must be located in internal packages.

No public class exposed as much as possible

Only interfaces should be exposed in the public API/SPI (as much as possible). This will satisfy binary compatibility and allow future extensibility. Of course, in some cases, it is not possible. For example, ServletTestCase has to be a class as it contains logic required to transform a JUnit test case into a Cactus test case. Same for ServletTestSuite as the way to use it in a JUnit suite() method is to create an instance of it.