<?xml version="1.0"?>

<!--
 * ========================================================================
 * 
 * Copyright 2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * ========================================================================
-->

<document id="apis">

  <properties>
    <title>Public API/SPI vs internal classes</title>
  </properties>

  <body>

    <section title="Cactus API design rules">

      <note>
        Most of these rules are extracted from the excellent 
        <a href="ext:eclipse_api_usage">How to Use the Eclipse API</a> article
        by Jim des Rivieres.
      </note>

      <section title="Public APIs/SPIs">

        <p>
          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.           
        </p>

        <ul>
          <li>
            <strong>API/SPI package</strong>: 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:             
          </li>
<source><![CDATA[
  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
]]></source>
          <li>
            <strong>API/SPI class or interface</strong>: 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.             
          </li>
          <li>
            <strong>API/SPI method or constructor</strong>: 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. 
          </li>
          <li>
            <strong>API/SPI field</strong>: 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.
          </li>
        </ul>
        <p>
          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: 
        </p>
        <ul>
          <li>
            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.
          </li>
        </ul>

      </section>

      <section title="No public methods in internal packages">

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

      <section title="No public class exposed as much as possible">

        <p>
          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, <code>ServletTestCase</code> has to be a class as it 
          contains logic required to transform a JUnit test case into a Cactus
          test case. Same for <code>ServletTestSuite</code> as the way to use 
          it in a JUnit <code>suite()</code> method is to create an instance 
          of it.
        </p>        
        
      </section>
      
    </section>

  </body>
</document>
