hivemind-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hls...@apache.org
Subject cvs commit: jakarta-hivemind/src/xsl hivemind.xsl
Date Sun, 18 Apr 2004 17:39:58 GMT
hlship      2004/04/18 10:39:58

  Modified:    .        .classpath
               framework/src/java/org/apache/hivemind/impl
                        RegistryBuilder.java ThreadedServiceModel.java
                        ServiceInterceptorContributionImpl.java
                        ConstructableServiceExtensionPoint.java
                        AbstractServiceModelImpl.java
                        ServiceExtensionPointImpl.java
               framework/src/java/org/apache/hivemind
                        HiveMindMessages.properties
                        ServiceInterceptorContribution.java HiveMind.java
               framework project.xml
               framework/src/test/hivemind/test/services TestShutdown.java
                        TestPooledServiceModel.java TestThreadedModel.java
                        AddSimpleInterceptors1.xml
                        AddSimpleInterceptors2.xml TestServices.java
               framework/src/java/org/apache/hivemind/parse
                        InterceptorDescriptor.java
                        DescriptorParser.properties DescriptorParser.java
               framework/src/test/hivemind/test TestMisc.java
               framework/src/test/hivemind/test/services/impl
                        TrackerFactory.java
               framework/src/test/hivemind/test/parse
                        TestDescriptorParser.java GenericModule.xml
                        BadElement.xml
               xdocs/images InterceptorStack.png
               xdocs    services.xml descriptor.xml
               src/images InterceptorStack.psp
               src/xsl  hivemind.xsl
  Added:       framework/src/java/org/apache/hivemind/order package.html
                        ObjectOrdering.java Orderer.java
               framework/src/test/hivemind/test/order TestOrderer.java
  Log:
  Add a dependency-based approach to ordering interceptors.
  
  Revision  Changes    Path
  1.24      +1 -0      jakarta-hivemind/.classpath
  
  Index: .classpath
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/.classpath,v
  retrieving revision 1.23
  retrieving revision 1.24
  diff -u -r1.23 -r1.24
  --- .classpath	7 Apr 2004 15:18:12 -0000	1.23
  +++ .classpath	18 Apr 2004 17:39:57 -0000	1.24
  @@ -20,5 +20,6 @@
       <classpathentry kind="var" path="MAVEN_REPO/oro/jars/oro-2.0.6.jar"/>
       <classpathentry kind="var" path="MAVEN_REPO/jboss/jars/javassist-2.6.jar"/>
       <classpathentry kind="var" path="MAVEN_REPO/jboss/jars/jboss-jmx-3.0.6.jar"/>
  +    <classpathentry kind="var" path="MAVEN_REPO/werkz/jars/werkz-1.0-beta-10.jar"/>
       <classpathentry kind="output" path="bin"/>
   </classpath>
  
  
  
  1.1                  jakarta-hivemind/framework/src/java/org/apache/hivemind/order/package.html
  
  Index: package.html
  ===================================================================
  <!-- $Id: package.html,v 1.1 2004/04/18 17:39:57 hlship Exp $ -->
  <!-- 
     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.
  -->
  	
  <body>
  
  Classes and interfaces for ordering objects based on dependencies. The underlying
  approach is provided by <a href="http://werkz.codehaus.org/">Werkz</a>.
  
  	</body>
  
  
  1.1                  jakarta-hivemind/framework/src/java/org/apache/hivemind/order/ObjectOrdering.java
  
  Index: ObjectOrdering.java
  ===================================================================
  //  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.
  
  package org.apache.hivemind.order;
  
  /**
   * Used by an {@link org.apache.hivemind.order.Orderer} to organize
   * a single object and pre- and post-requisites.
   * 
   * @author Howard Lewis Ship
   * @version $Id: ObjectOrdering.java,v 1.1 2004/04/18 17:39:57 hlship Exp $
   */
  class ObjectOrdering
  {
      private String _name;
      private Object _object;
      private String _prereqs;
      private String _postreqs;
  
      ObjectOrdering(Object object, String name, String prereqs, String postreqs)
      {
  
          _object = object;
  		_name = name;
          _prereqs = prereqs;
          _postreqs = postreqs;
      }
  
      public String getName()
      {
          return _name;
  
      }
      public Object getObject()
      {
          return _object;
      }
  
      public String getPostreqs()
      {
          return _postreqs;
      }
  
      public String getPrereqs()
      {
          return _prereqs;
      }
  
  }
  
  
  
  1.1                  jakarta-hivemind/framework/src/java/org/apache/hivemind/order/Orderer.java
  
  Index: Orderer.java
  ===================================================================
  //  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.
  
  package org.apache.hivemind.order;
  
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  
  import org.apache.commons.lang.StringUtils;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.apache.hivemind.HiveMind;
  
  import com.werken.werkz.Action;
  import com.werken.werkz.CyclicGoalChainException;
  import com.werken.werkz.DefaultAction;
  import com.werken.werkz.Goal;
  import com.werken.werkz.Session;
  import com.werken.werkz.WerkzProject;
  
  /**
   * Used to order objects into an "execution" order.  Each object must have a name.
   * It may specify a list of pre-requisites and a list of post-requisites.
   *
   * @author Howard Lewis Ship
   * @version $Id: Orderer.java,v 1.1 2004/04/18 17:39:57 hlship Exp $
   */
  public class Orderer
  {
      private final Log _log;
      private final String _objectType;
      private List _orderingsList = null;
      private Map _orderingsMap = null;
      private List _orderedObjects;
      private Goal _leader;
      private Goal _trailer;
  
      /**
       * Creates an instance using <code>org.apache.hivemind.order.Orderer</code> as the Log.
       */
      public Orderer(String objectType)
      {
          this(LogFactory.getLog(Orderer.class), objectType);
      }
  
      /**
       * Creates a new instance, but directs all debug and error logging output
       * to the provided log.
       * 
       * @param log Used for logging any errors
       * @param objectType user presentable name for the type of object to be ordered; used in some error messages
       */
      public Orderer(Log log, String objectType)
      {
          _log = log;
          _objectType = objectType;
  
          HiveMind.checkNullParameter("log", log);
          HiveMind.checkNullParameter("log", objectType);
      }
  
      /**
       * Adds a new object.  All invocations of {@link #add(Object, String, String, String)}
       * should occur before invoking {@link #getOrderedObjects()}.
       * 
       * @param object an object to be sorted into order based on prereqs and postreqs
       * @param name a unique name for the 
       * @param prereqs a comma-separated list of the names of objects that should precede this
       * object in the list (or null)
       * @param postreqs a comma-separated list of the names of objects that should follow this
       * object in the list (or null)
       */
      public void add(Object object, String name, String prereqs, String postreqs)
      {
          if (_orderingsMap == null)
          {
              _orderingsMap = new HashMap();
              _orderingsList = new ArrayList();
          }
  
          ObjectOrdering o = getOrderable(name);
  
          if (o != null)
          {
              _log.error(
                  HiveMind.format(
                      "Orderer.duplicate-name",
                      new Object[] {
                          StringUtils.capitalize(_objectType),
                          name,
                          HiveMind.getLocationString(object),
                          HiveMind.getLocationString(o.getObject())}));
              return;
          }
  
          o = new ObjectOrdering(object, name, prereqs, postreqs);
  
          _orderingsMap.put(name, o);
          _orderingsList.add(o);
      }
  
      private ObjectOrdering getOrderable(String name)
      {
          return (ObjectOrdering) _orderingsMap.get(name);
      }
  
      /**
       * Uses the information provided by {@link #add(Object, String, String, String)} to order
       * the objects into an appropriate order based on the pre- and post-reqts provided.
       * Errors such as cyclic dependencies or unrecognized names are logged and ignored.
       */
      public List getOrderedObjects()
      {
          if (_orderingsMap == null)
              return Collections.EMPTY_LIST;
  
          try
          {
              _orderedObjects = new ArrayList(_orderingsMap.size());
  
              runGoals();
  
              return _orderedObjects;
          }
          finally
          {
              _orderedObjects = null;
              _leader = null;
              _trailer = null;
          }
      }
  
      private static class NullAction extends DefaultAction
      {
  
          public void performAction() throws Exception
          {
  
          }
  
          public void performAction(Session arg0) throws Exception
          {
  
          }
  
      }
  
      private void runGoals()
      {
          WerkzProject p = new WerkzProject();
  
          addGoals(p);
  
          if (_leader == null)
          {
              _leader = new Goal("*-leader-*", new NullAction());
              p.addGoal(_leader);
          }
  
          if (_trailer == null)
          {
              _trailer = new Goal("*-trailer-*", new NullAction());
  
              p.addGoal(_trailer);
          }
  
          addDependencies(p);
  
          try
          {
              _trailer.attain(new Session());
          }
          catch (Exception ex)
          {
              _log.error(HiveMind.format("Orderer.exception", _objectType, ex.getMessage()), ex);
          }
      }
  
      private void addGoals(WerkzProject project)
      {
          Iterator i = _orderingsList.iterator();
  
          while (i.hasNext())
          {
              final ObjectOrdering o = (ObjectOrdering) i.next();
  
              Action a = new DefaultAction()
              {
                  public void performAction()
                  {
                      _orderedObjects.add(o.getObject());
                  }
  
                  public void performAction(Session session)
                  {
                      performAction();
                  }
              };
  
              Goal goal = new Goal(o.getName(), a);
  
              project.addGoal(goal);
  
              if ("*".equals(o.getPostreqs()))
              {
                  if (_leader == null)
                      _leader = goal;
                  else
                  {
                      String leaderName = _leader.getName();
                      _log.error(
                          HiveMind.format(
                              "Orderer.dupe-leader",
                              new Object[] {
                                  StringUtils.capitalize(_objectType),
                                  o.getName(),
                                  HiveMind.getLocationString(o.getObject()),
                                  leaderName,
                                  getLocationString(leaderName)}));
                  }
              }
  
              if ("*".equals(o.getPrereqs()))
              {
                  if (_trailer == null)
                      _trailer = goal;
                  else
                  {
                      String trailerName = _trailer.getName();
                      _log.error(
                          HiveMind.format(
                              "Orderer.dupe-trailer",
                              new Object[] {
                                  StringUtils.capitalize(_objectType),
                                  o.getName(),
                                  HiveMind.getLocationString(o.getObject()),
                                  trailerName,
                                  getLocationString(trailerName)}));
                  }
              }
  
          }
      }
  
      private void addDependencies(WerkzProject project)
      {
          Iterator i = _orderingsList.iterator();
  
          while (i.hasNext())
          {
              ObjectOrdering o = (ObjectOrdering) i.next();
              String name = o.getName();
  
              Goal goal = project.getGoal(name);
  
              addDependencies(project, goal, o);
          }
      }
  
      private void addDependencies(WerkzProject project, Goal goal, ObjectOrdering orderable)
      {
  
          addPrecursors(project, goal, orderable.getPrereqs());
          addPostcursors(project, goal, orderable.getPostreqs());
  
          try
          {
              if (goal != _leader)
                  _leader.addPostcursor(goal);
  
              if (goal != _trailer)
                  _trailer.addPrecursor(goal);
          }
          catch (CyclicGoalChainException ex)
          {
              // This code is unreachable ... but nonetheless.
  
              String name = goal.getName();
  
              _log.error(
                  HiveMind.format(
                      "Orderer.dependency-cycle",
                      new Object[] { _objectType, name, getLocationString(name), ex.getMessage()}),
                  ex);
          }
      }
  
      private void addPrecursors(WerkzProject project, Goal goal, String prereqs)
      {
          if ("*".equals(prereqs))
              return;
  
          String[] names = split(prereqs);
  
          for (int i = 0; i < names.length; i++)
          {
              String prename = names[i];
  
              Goal pregoal = project.getGoal(prename);
  
              if (pregoal == null)
              {
                  String name = goal.getName();
                  _log.error(
                      HiveMind.format(
                          "Orderer.bad-dependency",
                          new Object[] { _objectType, prename, name, getLocationString(name)}));
              }
              else
              {
  
                  try
                  {
                      goal.addPrecursor(pregoal);
                  }
                  catch (CyclicGoalChainException ex)
                  {
                      String name = goal.getName();
                      _log.error(
                          HiveMind.format(
                              "Orderer.dependency-cycle",
                              new Object[] {
                                  _objectType,
                                  name,
                                  getLocationString(name),
                                  ex.getMessage()}),
                          ex);
                  }
  
              }
          }
      }
  
      private void addPostcursors(WerkzProject project, Goal goal, String postreqs)
      {
          if ("*".equals(postreqs))
              return;
  
          String[] names = split(postreqs);
  
          for (int i = 0; i < names.length; i++)
          {
              String postname = names[i];
  
              Goal postgoal = project.getGoal(postname);
  
              if (postgoal == null)
              {
                  String name = goal.getName();
                  _log.error(
                      HiveMind.format(
                          "Orderer.bad-dependency",
                          new Object[] { _objectType, postname, name, getLocationString(name)}));
              }
              else
              {
  
                  try
                  {
                      goal.addPostcursor(postgoal);
                  }
                  catch (CyclicGoalChainException ex)
                  {
                      String name = goal.getName();
                      _log.error(
                          HiveMind.format(
                              "Orderer.dependency-cycle",
                              new Object[] {
                                  _objectType,
                                  name,
                                  getLocationString(name),
                                  ex.getMessage()}),
                          ex);
                  }
  
              }
          }
  
      }
  
      private String getLocationString(String name)
      {
          return HiveMind.getLocationString(getOrderable(name).getObject());
      }
  
      /**
       * Splits an input string into a an array of strings.
       */
      private String[] split(String input)
      {
          if (input == null)
              return new String[0];
  
          return StringUtils.split(input, ',');
      }
  }
  
  
  
  1.4       +27 -4     jakarta-hivemind/framework/src/java/org/apache/hivemind/impl/RegistryBuilder.java
  
  Index: RegistryBuilder.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/impl/RegistryBuilder.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- RegistryBuilder.java	15 Apr 2004 03:40:34 -0000	1.3
  +++ RegistryBuilder.java	18 Apr 2004 17:39:57 -0000	1.4
  @@ -25,6 +25,7 @@
   import java.util.Locale;
   import java.util.Map;
   
  +import org.apache.commons.lang.StringUtils;
   import org.apache.commons.logging.Log;
   import org.apache.commons.logging.LogFactory;
   import org.apache.hivemind.ApplicationRuntimeException;
  @@ -649,12 +650,14 @@
   
           ServiceExtensionPointImpl sep = (ServiceExtensionPointImpl) _servicePoints.get(pointId);
   
  +        String sourceModuleId = sourceModule.getModuleId();
  +
           if (sep == null)
           {
               LOG.error(
                   HiveMind.format(
                       "RegistryBuilder.unknown-service-extension-point",
  -                    sourceModule.getModuleId(),
  +                    sourceModuleId,
                       pointId,
                       id.getLocation()));
               return;
  @@ -665,13 +668,33 @@
           // Allow the factory id to be unqualified, to refer to an interceptor factory
           // service from within the same module.
   
  -        sic.setFactoryServiceId(qualify(sourceModule.getModuleId(), id.getFactoryServiceId()));
  +        sic.setFactoryServiceId(qualify(sourceModuleId, id.getFactoryServiceId()));
           sic.setLocation(id.getLocation());
  -        sic.setOrder(id.getOrder());
  +
  +        sic.setFollowingInterceptorIds(qualifyList(sourceModuleId, id.getBefore()));
  +        sic.setPrecedingInterceptorIds(qualifyList(sourceModuleId, id.getAfter()));
  +
           sic.setContributingModule(sourceModule);
           sic.setParameters(id.getParameters());
   
           sep.addInterceptorContribution(sic);
  +    }
  +
  +	/**
  +	 * Qualifies a list of interceptor service ids provided for an interceptor
  +	 * contribution.  The special value "*" is not qualified.
  +	 */
  +    private String qualifyList(String sourceModuleId, String list)
  +    {
  +        if (HiveMind.isBlank(list) || list.equals("*"))
  +            return list;
  +
  +        String[] items = StringUtils.split(list, ',');
  +
  +        for (int i = 0; i < items.length; i++)
  +            items[i] = qualify(sourceModuleId, items[i]);
  +
  +        return StringUtils.join(items, ',');
       }
   
       /**
  
  
  
  1.2       +7 -11     jakarta-hivemind/framework/src/java/org/apache/hivemind/impl/ThreadedServiceModel.java
  
  Index: ThreadedServiceModel.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/impl/ThreadedServiceModel.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ThreadedServiceModel.java	26 Feb 2004 23:07:40 -0000	1.1
  +++ ThreadedServiceModel.java	18 Apr 2004 17:39:57 -0000	1.2
  @@ -14,15 +14,13 @@
   
   package org.apache.hivemind.impl;
   
  -import org.apache.hivemind.service.ThreadCleanupListener;
  -import org.apache.hivemind.service.ThreadEventNotifier;
  -import org.apache.commons.logging.Log;
  -import org.apache.commons.logging.LogFactory;
   import org.apache.hivemind.ApplicationRuntimeException;
   import org.apache.hivemind.Discardable;
   import org.apache.hivemind.HiveMind;
   import org.apache.hivemind.Registry;
   import org.apache.hivemind.RegistryShutdownListener;
  +import org.apache.hivemind.service.ThreadCleanupListener;
  +import org.apache.hivemind.service.ThreadEventNotifier;
   
   /**
    * Like
  @@ -37,8 +35,6 @@
    */
   public final class ThreadedServiceModel extends AbstractServiceModelImpl
   {
  -    private static final Log LOG = LogFactory.getLog(ThreadedServiceModel.class);
  -
       /**
        * Name of a method in the deferred proxy that is used to obtain
        * the constructed service.
  @@ -92,9 +88,9 @@
        */
       public synchronized Object getServiceImplementation()
       {
  -    	// _activeService will be null on first invocation; a good
  -    	// time to create it, the proxy, and find the notifier.
  -    	
  +        // _activeService will be null on first invocation; a good
  +        // time to create it, the proxy, and find the notifier.
  +
           if (_activeService == null)
           {
               _activeService = new ThreadLocal();
  @@ -166,7 +162,7 @@
               initializeCoreServiceImplementation(core);
   
               if (core instanceof RegistryShutdownListener)
  -                LOG.error(
  +                _log.error(
                       HiveMind.format(
                           "ThreadedServiceModel.registry-cleanup-ignored",
                           getServicePoint().getExtensionPointId()));
  
  
  
  1.2       +25 -11    jakarta-hivemind/framework/src/java/org/apache/hivemind/impl/ServiceInterceptorContributionImpl.java
  
  Index: ServiceInterceptorContributionImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/impl/ServiceInterceptorContributionImpl.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ServiceInterceptorContributionImpl.java	26 Feb 2004 23:07:40 -0000	1.1
  +++ ServiceInterceptorContributionImpl.java	18 Apr 2004 17:39:57 -0000	1.2
  @@ -38,18 +38,20 @@
       implements ServiceInterceptorContribution
   {
       private String _factoryServiceId;
  -    private int _order;
       private Module _contributingModule;
       private List _parameters;
       private List _convertedParameters;
       private ServiceInterceptorFactory _factory;
  +    private String _precedingInterceptorIds;
  +    private String _followingInterceptorIds;
   
       public String toString()
       {
           ToStringBuilder builder = new ToStringBuilder(this);
           builder.append("factoryServiceId", _factoryServiceId);
  -        builder.append("order", _order);
           builder.append("parameters", _parameters);
  +        builder.append("precedingInterceptorIds", _precedingInterceptorIds);
  +        builder.append("followingInterceptorIds", _followingInterceptorIds);
   
           return builder.toString();
       }
  @@ -59,20 +61,12 @@
           return _factoryServiceId;
       }
   
  -    public int getOrder()
  -    {
  -        return _order;
  -    }
   
       public void setFactoryServiceId(String string)
       {
           _factoryServiceId = string;
       }
   
  -    public void setOrder(int i)
  -    {
  -        _order = i;
  -    }
   
       public void createInterceptor(InterceptorStack stack)
       {
  @@ -116,6 +110,26 @@
       public void setParameters(List list)
       {
           _parameters = list;
  +    }
  +
  +    public String getFollowingInterceptorIds()
  +    {
  +        return _followingInterceptorIds;
  +    }
  +
  +    public String getPrecedingInterceptorIds()
  +    {
  +        return _precedingInterceptorIds;
  +    }
  +
  +    public void setFollowingInterceptorIds(String string)
  +    {
  +        _followingInterceptorIds = string;
  +    }
  +
  +    public void setPrecedingInterceptorIds(String string)
  +    {
  +        _precedingInterceptorIds = string;
       }
   
   }
  
  
  
  1.2       +33 -5     jakarta-hivemind/framework/src/java/org/apache/hivemind/impl/ConstructableServiceExtensionPoint.java
  
  Index: ConstructableServiceExtensionPoint.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/impl/ConstructableServiceExtensionPoint.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ConstructableServiceExtensionPoint.java	26 Feb 2004 23:07:40 -0000	1.1
  +++ ConstructableServiceExtensionPoint.java	18 Apr 2004 17:39:57 -0000	1.2
  @@ -36,11 +36,39 @@
       public ServiceImplementationConstructor getServiceConstructor();
   
       /**
  -     * Returns a list of {@link org.apache.hivemind.ServiceInterceptorContribution}s, sorted
  -     * into ascending order. May return an empty list if there are no
  -     * interceptors, but won't return null.
  +     * Returns a list of {@link org.apache.hivemind.ServiceInterceptorContribution}s, 
  +     * ordered according to their dependencies.  May return null or an empty list.
  +     * 
  +     * <p>
  +     * Note that the order is tricky! To keep any error messages while ordering
  +     * the interceptors understandable, they are ordered according into runtime
  +     * execution order.  Example: If we want a logging interceptor
  +     * to operate before a security-check interceptor, we'll write the following
  +     * in the descriptor:
  +     * 
  +     * <pre>
  +     *   &lt;interceptor service-id="hivemind.LoggingInterceptor" before="*"/&gt;
  +     *   &lt;interceptor service-id="somepackage.SecurityInterceptor"/&gt;
  +     * </pre>
  +     * 
  +     * The <code>before</code> value for the first interceptor contribution
  +     * will be assigned to the contribution's
  +     * {@link org.apache.hivemind.ServiceInterceptorContribution#getFollowingInterceptorIds() followingInterceptorIds}
  +     * property, because all other interceptors (including the security interceptor)
  +     * should have their behavior follow the logging interceptor.
  +     * 
  +     * <p>
  +     * To get this behavior, the logging interceptor will delegate to the security
  +     * interceptor, and the security interceptor will delegate to
  +     * the core service implementation.
  +     * 
  +     * <p>
  +     * The trick is that interceptors are applied in reverse order: we start
  +     * with core service implementation, wrap it with the security interceptor, then
  +     * wrap that with the logging interceptor ... but that's an issue that applies
  +     * when building the interceptor stack around the core service implementation.
        */
  -    public List getSortedInterceptors();
  +    public List getOrderedInterceptorContributions();
   
       /**
        * Invoked by the ServiceModel when constuction information
  
  
  
  1.3       +25 -8     jakarta-hivemind/framework/src/java/org/apache/hivemind/impl/AbstractServiceModelImpl.java
  
  Index: AbstractServiceModelImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/impl/AbstractServiceModelImpl.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- AbstractServiceModelImpl.java	29 Feb 2004 20:57:08 -0000	1.2
  +++ AbstractServiceModelImpl.java	18 Apr 2004 17:39:57 -0000	1.3
  @@ -34,12 +34,20 @@
    */
   public abstract class AbstractServiceModelImpl implements ServiceModel
   {
  -    private static final Log LOG = LogFactory.getLog(AbstractServiceModelImpl.class);
  +    /**
  +     * This log is created from the log's service id, which is the appropriate
  +     * place to log any messages related to creating (or managing) the
  +     * service implementation, proxy, etc.  Subclasses should make
  +     * use of this Log as well.
  +     */
  +    protected final Log _log;
   
       private ConstructableServiceExtensionPoint _servicePoint;
   
       public AbstractServiceModelImpl(ConstructableServiceExtensionPoint servicePoint)
       {
  +        _log = LogFactory.getLog(servicePoint.getExtensionPointId());
  +
           _servicePoint = servicePoint;
       }
   
  @@ -61,16 +69,25 @@
   
       protected Object addInterceptors(Object core)
       {
  -        List interceptors = _servicePoint.getSortedInterceptors();
  +        List interceptors = _servicePoint.getOrderedInterceptorContributions();
   
  -        int count = interceptors.size();
  +        int count = interceptors == null ? 0 : interceptors.size();
   
           if (count == 0)
               return core;
   
           InterceptorStackImpl stack = new InterceptorStackImpl(_servicePoint, core);
   
  -        for (int i = 0; i < count; i++)
  +        // They are sorted into runtime execution order. Since we build from the
  +        // core service impl outwarads, we have to reverse the runtime execution
  +        // order to get the build order.
  +        // That is, if user expects interceptors in order A B C (perhaps using
  +        // the rules: A before B, C after B).
  +        // Then that's the order for interceptors list: A B C  
  +        // To get that runtime execution order, we wrap C around the core,
  +        // wrap B around C, and wrap A around B.
  +
  +        for (int i = count - 1; i >= 0; i--)
           {
               ServiceInterceptorContribution ic =
                   (ServiceInterceptorContribution) interceptors.get(i);
  @@ -96,8 +113,8 @@
          */
       protected Object constructCoreServiceImplementation()
       {
  -        if (LOG.isDebugEnabled())
  -            LOG.debug(
  +        if (_log.isDebugEnabled())
  +            _log.debug(
                   "Constructing core instance for service " + _servicePoint.getExtensionPointId());
   
           Class serviceType = _servicePoint.getServiceInterface();
  @@ -122,7 +139,7 @@
                   constructor.getLocation(),
                   null);
   
  -		HiveMind.setLocation(result, constructor.getLocation());
  +        HiveMind.setLocation(result, constructor.getLocation());
   
           return result;
       }
  
  
  
  1.2       +44 -7     jakarta-hivemind/framework/src/java/org/apache/hivemind/impl/ServiceExtensionPointImpl.java
  
  Index: ServiceExtensionPointImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/impl/ServiceExtensionPointImpl.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ServiceExtensionPointImpl.java	26 Feb 2004 23:07:40 -0000	1.1
  +++ ServiceExtensionPointImpl.java	18 Apr 2004 17:39:57 -0000	1.2
  @@ -15,15 +15,19 @@
   package org.apache.hivemind.impl;
   
   import java.util.ArrayList;
  +import java.util.Iterator;
   import java.util.List;
   
   import org.apache.commons.lang.builder.ToStringBuilder;
  +import org.apache.commons.logging.Log;
  +import org.apache.commons.logging.LogFactory;
   import org.apache.hivemind.ApplicationRuntimeException;
   import org.apache.hivemind.ClassResolver;
   import org.apache.hivemind.HiveMind;
   import org.apache.hivemind.ServiceImplementationConstructor;
   import org.apache.hivemind.ServiceInterceptorContribution;
   import org.apache.hivemind.ServiceModel;
  +import org.apache.hivemind.order.Orderer;
   import org.apache.hivemind.schema.Schema;
   
   /**
  @@ -44,7 +48,7 @@
       private Class _serviceInterface;
       private ServiceImplementationConstructor _serviceConstructor;
       private List _interceptorContributions;
  -    private boolean _interceptorsSorted;
  +    private boolean _interceptorsOrdered;
       private Schema _parametersSchema;
       private ServiceModel _serviceModel;
       private ShutdownCoordinator _shutdownCoordinator;
  @@ -178,16 +182,49 @@
   
       // Hm. Does this need to be synchronized?
   
  -    public List getSortedInterceptors()
  +    public List getOrderedInterceptorContributions()
       {
  -        if (!_interceptorsSorted)
  +        if (!_interceptorsOrdered)
           {
  -
  -            _interceptorContributions = HiveMind.sortOrderables(_interceptorContributions);
  -            _interceptorsSorted = true;
  +            _interceptorContributions = orderInterceptors();
  +            _interceptorsOrdered = true;
           }
   
           return _interceptorContributions;
  +    }
  +
  +    private List orderInterceptors()
  +    {
  +        if (HiveMind.isEmpty(_interceptorContributions))
  +            return null;
  +
  +        // Any error logging should go to the extension point
  +        // we're constructing.
  +
  +        Log log = LogFactory.getLog(getExtensionPointId());
  +
  +        Orderer orderer =
  +            new Orderer(
  +                log,
  +                HiveMind.getMessage("ServiceExtensionPointImpl.interceptor-contribution"));
  +
  +        Iterator i = _interceptorContributions.iterator();
  +        while (i.hasNext())
  +        {
  +            ServiceInterceptorContribution sic = (ServiceInterceptorContribution) i.next();
  +
  +			// Sort them into runtime excecution order. When we build 
  +			// the interceptor stack we'll apply them in reverse order,
  +			// building outward from the core service implementation.
  +
  +            orderer.add(
  +                sic,
  +                sic.getFactoryServiceId(),
  +                sic.getPrecedingInterceptorIds(),
  +                sic.getFollowingInterceptorIds());
  +        }
  +
  +        return orderer.getOrderedObjects();
       }
   
       public ShutdownCoordinator getShutdownCoordinator()
  
  
  
  1.7       +15 -1     jakarta-hivemind/framework/src/java/org/apache/hivemind/HiveMindMessages.properties
  
  Index: HiveMindMessages.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/HiveMindMessages.properties,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- HiveMindMessages.properties	15 Apr 2004 03:40:34 -0000	1.6
  +++ HiveMindMessages.properties	18 Apr 2004 17:39:57 -0000	1.7
  @@ -1,3 +1,4 @@
  +
   # $Id$
   #
   # Copyright 2004 The Apache Software Foundation
  @@ -19,6 +20,8 @@
   no-such-service-extension-id=Service extension point {0} does not exist.
   no-such-service=Service {0} (implementing interface {1}) does not exist.
   
  +null-parameter-invalid=Parameter {0} may not be null.
  +
   unknown-location=unknown location
   
   wrong-factory-parameter-count=Service implementation factory {0} expects {1,choice,0#no parameters|1#one parameter|1<{1,number,integer} parameters} but received {2,choice,0#none|1#one|1<{2,number,integer}}.
  @@ -47,6 +50,8 @@
   ServiceExtensionPoint.factory-wrong-interface=Instance factory for service {0} returned {1} which does not implement the {2} interface declared by the extension point.
   ServiceExtensionPoint.recursive-service-build=A recursive call to construct service {0} has occured.  This indicates a cycle between one or more services or configurations.
   
  +ServiceExtensionPointImpl.interceptor-contribution=interceptor contribution
  +
   DescriptorParser.missing-resource=Unable to find resource {0}.
   DescriptorParser.error-reading-descriptor=Unable to read descriptor {0}: {1}
   DescriptorParser.unknown-attribute=Unknown attribute ''{0}'' in element {1} (at {2}).
  @@ -189,3 +194,12 @@
   
   ConstructorUtils.no-matching-constructor=Unable to find a constructor for class {0}.
   ConstructorUtils.invoke-failed=Failure invoking constructor for class {0} (at {1}): {2}
  +
  +# order package
  +
  +Orderer.duplicate-name={0} ''{1}'' (at {2}) duplicates previous value (at {3}) and is being ignored.
  +Orderer.bad-dependency=Unknown {0} dependency ''{1}'' (for ''{2}'', at {3}).
  +Orderer.dependency-cycle=Unable to order {0} ''{1}'' (at {2}) due to dependency cycle: {3}
  +Orderer.exception=Unable to order {0}s: {1}
  +Orderer.dupe-leader={0} ''{1}'' (at {2}) has been ordered first, conflicting with ''{3}'' (at {4}).
  +Orderer.dupe-trailer={0} ''{1}'' (at {2}) has been ordered last, conflicting with ''{3}'' (at {4}).
  \ No newline at end of file
  
  
  
  1.2       +20 -2     jakarta-hivemind/framework/src/java/org/apache/hivemind/ServiceInterceptorContribution.java
  
  Index: ServiceInterceptorContribution.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/ServiceInterceptorContribution.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ServiceInterceptorContribution.java	26 Feb 2004 23:07:56 -0000	1.1
  +++ ServiceInterceptorContribution.java	18 Apr 2004 17:39:57 -0000	1.2
  @@ -21,7 +21,7 @@
    * @author Howard Lewis Ship
    * @version $Id$
    */
  -public interface ServiceInterceptorContribution extends Locatable, Orderable
  +public interface ServiceInterceptorContribution extends Locatable
   {	
       /**
        * Returns the id of the factory that creates the interceptor.
  @@ -34,4 +34,22 @@
        * Invoked to actually create the interceptor and push it onto the stack.
        */
   	public void createInterceptor(InterceptorStack stack);
  +	
  +	/**
  +	 * Returns a list interceptors service ids as a comma seperated list.
  +	 * The behavior provided by these interceptors should
  +	 * <em>precede</em> the behavior of this interceptor.
  +	 * 
  +	 * <p>Each service id is fully qualified. May return null.
  +	 */
  +	
  +	public String getPrecedingInterceptorIds();
  +	
  +	/**
  +	 * 
  +	 * As {@link #getPrecedingInterceptorIds()}, but the indicating
  +	 * interceptors's behavior should <em>follow</em> this interceptor's.
  +	 */
  +	
  +	public String getFollowingInterceptorIds();
   }
  
  
  
  1.4       +28 -8     jakarta-hivemind/framework/src/java/org/apache/hivemind/HiveMind.java
  
  Index: HiveMind.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/HiveMind.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- HiveMind.java	29 Feb 2004 20:57:09 -0000	1.3
  +++ HiveMind.java	18 Apr 2004 17:39:57 -0000	1.4
  @@ -16,6 +16,7 @@
   
   import java.text.MessageFormat;
   import java.util.ArrayList;
  +import java.util.Collection;
   import java.util.Collections;
   import java.util.Comparator;
   import java.util.List;
  @@ -273,13 +274,13 @@
           return !isBlank(string);
       }
   
  -	/**
  -	 * Updates the location of an object, if the object implements
  -	 * {@link LocationHolder}.
  -	 * 
  -	 * @param holder the object to be updated
  -	 * @param location the location to assign to the holder object
  -	 */
  +    /**
  +     * Updates the location of an object, if the object implements
  +     * {@link LocationHolder}.
  +     * 
  +     * @param holder the object to be updated
  +     * @param location the location to assign to the holder object
  +     */
       public static void setLocation(Object holder, Location location)
       {
           if (holder != null && holder instanceof LocationHolder)
  @@ -288,5 +289,24 @@
   
               lh.setLocation(location);
           }
  +    }
  +
  +    /**
  +     * Checks if the value (a constructor or method parameter) is null,
  +     * and throws an InvalidArgumentException if so.
  +     */
  +
  +    public static void checkNullParameter(String parameterName, Object value)
  +    {
  +        if (value == null)
  +            throw new IllegalArgumentException(format("null-parameter-invalid", parameterName));
  +    }
  +    
  +   	/**
  +   	 * Returns true if the Collection is null or empty.
  +   	 */
  +    public static boolean isEmpty(Collection c)
  +    {
  +    	return c == null || c.isEmpty();
       }
   }
  
  
  
  1.14      +8 -1      jakarta-hivemind/framework/project.xml
  
  Index: project.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/project.xml,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- project.xml	5 Apr 2004 20:03:59 -0000	1.13
  +++ project.xml	18 Apr 2004 17:39:57 -0000	1.14
  @@ -78,6 +78,13 @@
       	<version>2.3</version>
       </dependency>
       
  +    <!-- For handling ordering of operations (such as interceptors) -->
  +    
  +    <dependency>
  +    	<id>werkz</id>	
  +    	<version>1.0-beta-10</version>
  +    </dependency>
  +    
   		<!-- For building the Ant tasks -->
   		
       <dependency>
  
  
  
  1.1                  jakarta-hivemind/framework/src/test/hivemind/test/order/TestOrderer.java
  
  Index: TestOrderer.java
  ===================================================================
  //  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.
  
  package hivemind.test.order;
  
  import hivemind.test.FrameworkTestCase;
  
  import java.util.List;
  
  import org.apache.hivemind.order.Orderer;
  
  /**
   * Tests for the {@link org.apache.hivemind.order.Orderer}.
   *
   * @author Howard Lewis Ship
   * @version $Id: TestOrderer.java,v 1.1 2004/04/18 17:39:57 hlship Exp $
   */
  public class TestOrderer extends FrameworkTestCase
  {
      public void testNoDependencies() throws Exception
      {
          Orderer o = new Orderer("cartoon character");
  
          o.add("FRED", "fred", null, null);
          o.add("BARNEY", "barney", null, null);
          o.add("WILMA", "wilma", null, null);
          o.add("BETTY", "betty", null, null);
  
          List l = o.getOrderedObjects();
  
          assertListsEqual(new Object[] { "FRED", "BARNEY", "WILMA", "BETTY" }, l);
      }
  
      public void testPrereq() throws Exception
      {
          Orderer o = new Orderer("cartoon character");
  
          o.add("FRED", "fred", "wilma", null);
          o.add("BARNEY", "barney", "betty", null);
          o.add("BETTY", "betty", null, null);
          o.add("WILMA", "wilma", null, null);
  
          List l = o.getOrderedObjects();
  
          assertListsEqual(new Object[] { "WILMA", "FRED", "BETTY", "BARNEY" }, l);
      }
  
      public void testPostreq() throws Exception
      {
          Orderer o = new Orderer("cartoon character");
  
          o.add("FRED", "fred", null, "barney,wilma");
          o.add("BARNEY", "barney", null, "betty");
          o.add("BETTY", "betty", null, null);
          o.add("WILMA", "wilma", null, null);
  
          List l = o.getOrderedObjects();
  
          assertListsEqual(new Object[] { "FRED", "BARNEY", "BETTY", "WILMA" }, l);
      }
  
      public void testPrePostreq() throws Exception
      {
          Orderer o = new Orderer("cartoon character");
  
          o.add("FRED", "fred", null, "barney,wilma");
          o.add("BARNEY", "barney", "wilma", "betty");
          o.add("BETTY", "betty", null, null);
          o.add("WILMA", "wilma", null, null);
  
          List l = o.getOrderedObjects();
  
          assertListsEqual(new Object[] { "FRED", "WILMA", "BARNEY", "BETTY" }, l);
      }
  
      public void testUnknownPrereq() throws Exception
      {
          Orderer o = new Orderer("cartoon character");
  
          o.add("FRED", "fred", "charlie", "barney,wilma");
          o.add("BARNEY", "barney", "wilma", "betty");
          o.add("BETTY", "betty", null, null);
          o.add("WILMA", "wilma", null, null);
  
          interceptLogging();
  
          List l = o.getOrderedObjects();
  
          assertListsEqual(new Object[] { "FRED", "WILMA", "BARNEY", "BETTY" }, l);
  
          assertLoggedMessage("Unknown cartoon character dependency 'charlie' (for 'fred', at unknown location).");
  
      }
  
      public void testUnknownPostreq() throws Exception
      {
          Orderer o = new Orderer("cartoon character");
  
          o.add("FRED", "fred", null, "barney,wilma");
          o.add("BARNEY", "barney", "wilma", "betty");
          o.add("BETTY", "betty", null, "dino");
          o.add("WILMA", "wilma", null, null);
  
          interceptLogging();
  
          List l = o.getOrderedObjects();
  
          assertListsEqual(new Object[] { "FRED", "WILMA", "BARNEY", "BETTY" }, l);
  
          assertLoggedMessage("Unknown cartoon character dependency 'dino' (for 'betty', at unknown location).");
      }
  
      public void testCyclePre() throws Exception
      {
          Orderer o = new Orderer("cartoon character");
  
          o.add("FRED", "fred", "wilma", null);
          o.add("BARNEY", "barney", "betty", null);
          o.add("BETTY", "betty", "fred", null);
          o.add("WILMA", "wilma", "barney", null);
  
          interceptLogging();
  
          List l = o.getOrderedObjects();
  
          assertListsEqual(new Object[] { "WILMA", "FRED", "BETTY", "BARNEY" }, l);
  
          assertLoggedMessage(
              "Unable to order cartoon character 'wilma' (at unknown location) due to dependency cycle:"
                  + " A cycle has been detected from the initial goal [wilma]");
      }
  
      public void testCyclePost() throws Exception
      {
          Orderer o = new Orderer("cartoon character");
  
          o.add("WILMA", "wilma", null, "betty");
          o.add("FRED", "fred", null, "barney");
          o.add("BARNEY", "barney", null, "wilma");
          o.add("BETTY", "betty", null, "fred");
  
          interceptLogging();
  
          List l = o.getOrderedObjects();
          assertListsEqual(new Object[] { "FRED", "BARNEY", "WILMA", "BETTY" }, l);
  
          assertLoggedMessage(
              "Unable to order cartoon character 'betty' (at unknown location) due to dependency cycle:"
                  + " A cycle has been detected from the initial goal [fred]");
      }
  
      public void testDupe() throws Exception
      {
          Orderer o = new Orderer("cartoon character");
  
          o.add("FRED", "flintstone", null, null);
          o.add("BARNEY", "rubble", null, null);
  
          interceptLogging();
  
          o.add("WILMA", "flintstone", null, null);
  
          assertLoggedMessage("Cartoon character 'flintstone' (at unknown location) duplicates previous value (at unknown location) and is being ignored.");
  
          List l = o.getOrderedObjects();
  
          assertListsEqual(new Object[] { "FRED", "BARNEY" }, l);
      }
  
      public void testPreStar() throws Exception
      {
          Orderer o = new Orderer("cartoon character");
  
          o.add("FRED", "fred", "*", null);
          o.add("BARNEY", "barney", "betty", null);
          o.add("WILMA", "wilma", "betty", null);
          o.add("BETTY", "betty", null, null);
  
          List l = o.getOrderedObjects();
  
          assertListsEqual(new Object[] { "BETTY", "BARNEY", "WILMA", "FRED" }, l);
      }
  
      public void testPreStartDupe() throws Exception
      {
          Orderer o = new Orderer("cartoon character");
  
          o.add("FRED", "fred", "*", null);
          o.add("BARNEY", "barney", "*", null);
          o.add("WILMA", "wilma", "betty", null);
          o.add("BETTY", "betty", null, null);
  
          interceptLogging();
  
          List l = o.getOrderedObjects();
  
          assertListsEqual(new Object[] { "BARNEY", "BETTY", "WILMA", "FRED" }, l);
  
          assertLoggedMessage(
              "Cartoon character 'barney' (at unknown location) has been ordered "
                  + "last, conflicting with 'fred' (at unknown location).");
      }
  
      public void testPostStar() throws Exception
      {
          Orderer o = new Orderer("cartoon character");
  
          o.add("FRED", "fred", null, "wilma");
          o.add("BARNEY", "barney", null, "*");
          o.add("WILMA", "wilma", null, "betty");
          o.add("BETTY", "betty", null, null);
  
          List l = o.getOrderedObjects();
  
          assertListsEqual(new Object[] { "BARNEY", "FRED", "WILMA", "BETTY" }, l);
      }
  
      public void testPostStarDupe() throws Exception
      {
          Orderer o = new Orderer("cartoon character");
  
          o.add("FRED", "fred", null, "wilma");
          o.add("BARNEY", "barney", null, "*");
          o.add("WILMA", "wilma", null, "*");
          o.add("BETTY", "betty", null, null);
  
          interceptLogging();
  
          List l = o.getOrderedObjects();
  
          assertListsEqual(new Object[] { "BARNEY", "FRED", "WILMA", "BETTY" }, l);
  
          assertLoggedMessage(
              "Cartoon character 'wilma' (at unknown location) has been ordered "
                  + "first, conflicting with 'barney' (at unknown location).");
      }
  
      public void testNoObjects() throws Exception
      {
          Orderer o = new Orderer("cartoon character");
  
          List l = o.getOrderedObjects();
  
          assertEquals(0, l.size());
      }
  
  }
  
  
  
  1.4       +3 -3      jakarta-hivemind/framework/src/test/hivemind/test/services/TestShutdown.java
  
  Index: TestShutdown.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/services/TestShutdown.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- TestShutdown.java	26 Feb 2004 23:07:36 -0000	1.3
  +++ TestShutdown.java	18 Apr 2004 17:39:58 -0000	1.4
  @@ -106,7 +106,7 @@
   
           Runnable s = (Runnable) r.getService("hivemind.test.services.Singleton", Runnable.class);
   
  -        interceptLogging("hivemind.test");
  +        interceptLogging("hivemind.test.services.Singleton");
   
           s.run();
   
  @@ -123,7 +123,7 @@
   
           Runnable s = (Runnable) r.getService("hivemind.test.services.Primitive", Runnable.class);
   
  -        interceptLogging("hivemind.test");
  +        interceptLogging("hivemind.test.services.Primitive");
   
           s.run();
   
  
  
  
  1.4       +2 -2      jakarta-hivemind/framework/src/test/hivemind/test/services/TestPooledServiceModel.java
  
  Index: TestPooledServiceModel.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/services/TestPooledServiceModel.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- TestPooledServiceModel.java	26 Feb 2004 23:07:36 -0000	1.3
  +++ TestPooledServiceModel.java	18 Apr 2004 17:39:58 -0000	1.4
  @@ -39,7 +39,7 @@
           StringHolder s =
               (StringHolder) r.getService("hivemind.test.services.Managed", StringHolder.class);
   
  -        interceptLogging("hivemind.test");
  +        interceptLogging("hivemind.test.services.Managed");
   
           assertNull(s.getValue());
   
  
  
  
  1.8       +6 -2      jakarta-hivemind/framework/src/test/hivemind/test/services/TestThreadedModel.java
  
  Index: TestThreadedModel.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/services/TestThreadedModel.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- TestThreadedModel.java	26 Feb 2004 23:07:36 -0000	1.7
  +++ TestThreadedModel.java	18 Apr 2004 17:39:58 -0000	1.8
  @@ -72,12 +72,14 @@
   
           assertLoggedMessages(
               new String[] {
  +                "Constructing core instance for service hivemind.test.services.StringHolder",
                   "BEGIN getValue()",
                   "END getValue() [<null>]",
                   "BEGIN setValue(fred)",
                   "END setValue()",
                   "BEGIN getValue()",
                   "END getValue() [fred]",
  +                "Constructing core instance for service hivemind.test.services.StringHolder",
                   "BEGIN getValue()",
                   "END getValue() [<null>]" });
   
  @@ -121,12 +123,14 @@
   
           assertLoggedMessages(
               new String[] {
  +                "Constructing core instance for service hivemind.test.services.StringHolder",
                   "BEGIN getValue()",
                   "END getValue() [<null>]",
                   "BEGIN setValue(fred)",
                   "END setValue()",
                   "BEGIN getValue()",
                   "END getValue() [fred]",
  +                "Constructing core instance for service hivemind.test.services.StringHolder",
                   "BEGIN getValue()",
                   "END getValue() [<null>]",
                   "BEGIN setValue(barney)",
  @@ -156,7 +160,7 @@
                   "hivemind.test.services.ThreadedRegistryShutdown",
                   StringHolder.class);
   
  -        interceptLogging();
  +        interceptLogging("hivemind.test.services");
   
           h.setValue("foo");
   
  @@ -183,7 +187,7 @@
                   "hivemind.ThreadEventNotifier",
                   ThreadEventNotifier.class);
   
  -        interceptLogging("hivemind");
  +        interceptLogging("hivemind.test.services");
   
           n.fireThreadCleanup();
   
  
  
  
  1.3       +2 -2      jakarta-hivemind/framework/src/test/hivemind/test/services/AddSimpleInterceptors1.xml
  
  Index: AddSimpleInterceptors1.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/services/AddSimpleInterceptors1.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- AddSimpleInterceptors1.xml	18 Sep 2003 19:00:59 -0000	1.2
  +++ AddSimpleInterceptors1.xml	18 Apr 2004 17:39:58 -0000	1.3
  @@ -4,6 +4,6 @@
   	id="hivemind.test.services.add1" 
   	version="1.0.0">
   	<implementation service-id="hivemind.test.services.Simple">
  -	  <interceptor service-id="hivemind.test.services.tracker.Wilma" order="100"/>
  +	  <interceptor service-id="hivemind.test.services.tracker.Wilma" before="hivemind.test.services.tracker.Barney"/>
   	</implementation>
   </module>
  
  
  
  1.3       +3 -3      jakarta-hivemind/framework/src/test/hivemind/test/services/AddSimpleInterceptors2.xml
  
  Index: AddSimpleInterceptors2.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/services/AddSimpleInterceptors2.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- AddSimpleInterceptors2.xml	18 Sep 2003 19:00:59 -0000	1.2
  +++ AddSimpleInterceptors2.xml	18 Apr 2004 17:39:58 -0000	1.3
  @@ -4,7 +4,7 @@
   	id="hivemind.test.services.add2" 
   	version="1.0.0">
   	<implementation service-id="hivemind.test.services.Simple">
  -	  <interceptor service-id="hivemind.test.services.tracker.Barney" order="50"/>
  -	  <interceptor service-id="hivemind.test.services.tracker.Fred" order="10"/>
  +	  <interceptor service-id="hivemind.test.services.tracker.Barney"/>
  +	  <interceptor service-id="hivemind.test.services.tracker.Fred" after="hivemind.test.services.tracker.Barney"/>
   	</implementation>
   </module>
  
  
  
  1.11      +17 -9     jakarta-hivemind/framework/src/test/hivemind/test/services/TestServices.java
  
  Index: TestServices.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/services/TestServices.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- TestServices.java	7 Apr 2004 15:18:12 -0000	1.10
  +++ TestServices.java	18 Apr 2004 17:39:58 -0000	1.11
  @@ -84,10 +84,10 @@
           assertEquals(2, CountFactory.getCount());
       }
   
  -	// Note: this works when run by Maven, but for some reason
  -	// is failing inside Eclipse.  It appears the be a Log4J 
  -	// configuration problem ... but I have no idea why.
  -	
  +    // Note: this works when run by Maven, but for some reason
  +    // is failing inside Eclipse.  It appears the be a Log4J 
  +    // configuration problem ... but I have no idea why.
  +
       public void testInterceptorSort() throws Exception
       {
           Registry r =
  @@ -134,7 +134,11 @@
   
           s.add(5, 3);
   
  -        assertLoggedMessages(new String[] { "BEGIN add(5, 3)", "END add() [8]" });
  +        assertLoggedMessages(
  +            new String[] {
  +                "Constructing core instance for service hivemind.test.services.Demo",
  +                "BEGIN add(5, 3)",
  +                "END add() [8]" });
   
           s.noResult();
   
  @@ -214,7 +218,7 @@
   
           ToString ts = (ToString) r.getService("hivemind.test.services.ToString", ToString.class);
   
  -        interceptLogging("hivemind.test");
  +        interceptLogging("hivemind.test.services.ToString");
   
           assertEquals("ToStringImpl of toString()", ts.toString());
   
  @@ -237,7 +241,7 @@
   
           assertEquals("hivemind.test.services.BuilderAccess", s.getExtensionPointId());
   
  -        interceptLogging("hivemind");
  +        interceptLogging("hivemind.test.services.BuilderAccess");
   
           s.logMessage("This is a test.");
   
  @@ -321,7 +325,11 @@
   
           // Only fred and wilma should be logged.
   
  -        assertLoggedMessages(new String[] { "BEGIN fred()", "BEGIN wilma()" });
  +        assertLoggedMessages(
  +            new String[] {
  +                "Constructing core instance for service hivemind.test.services.Bedrock",
  +                "BEGIN fred()",
  +                "BEGIN wilma()" });
       }
   
   }
  
  
  
  1.3       +20 -7     jakarta-hivemind/framework/src/java/org/apache/hivemind/parse/InterceptorDescriptor.java
  
  Index: InterceptorDescriptor.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/parse/InterceptorDescriptor.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- InterceptorDescriptor.java	14 Apr 2004 21:11:51 -0000	1.2
  +++ InterceptorDescriptor.java	18 Apr 2004 17:39:58 -0000	1.3
  @@ -24,20 +24,33 @@
    */
   public final class InterceptorDescriptor extends AbstractServiceInvocationDescriptor
   {
  -    private int _order;
  +    private String _before;
  +    private String _after;
   
  -    public int getOrder()
  +    public String getAfter()
       {
  -        return _order;
  +        return _after;
       }
   
  -    public void setOrder(int i)
  +    public String getBefore()
       {
  -        _order = i;
  +        return _before;
  +    }
  +
  +    public void setAfter(String string)
  +    {
  +        _after = string;
  +    }
  +
  +    public void setBefore(String string)
  +    {
  +        _before = string;
       }
   
       protected void extendDescription(ToStringBuilder builder)
       {
  -        builder.append("order", _order);
  +        builder.append("before", _before);
  +        builder.append("after", _after);
       }
  +
   }
  
  
  
  1.2       +3 -2      jakarta-hivemind/framework/src/java/org/apache/hivemind/parse/DescriptorParser.properties
  
  Index: DescriptorParser.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/parse/DescriptorParser.properties,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- DescriptorParser.properties	15 Apr 2004 03:40:34 -0000	1.1
  +++ DescriptorParser.properties	18 Apr 2004 17:39:58 -0000	1.2
  @@ -36,7 +36,8 @@
   required.create-instance.class=true
   required.create-instance.model=false
   
  -required.interceptor.order=false
  +required.interceptor.before=false
  +required.interceptor.after=false
   required.interceptor.service-id=true
   
   required.element.name=true
  
  
  
  1.7       +3 -3      jakarta-hivemind/framework/src/java/org/apache/hivemind/parse/DescriptorParser.java
  
  Index: DescriptorParser.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/parse/DescriptorParser.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- DescriptorParser.java	15 Apr 2004 03:40:34 -0000	1.6
  +++ DescriptorParser.java	18 Apr 2004 17:39:58 -0000	1.7
  @@ -1052,8 +1052,8 @@
   
               id.setFactoryServiceId(getAttribute("service-id"));
   
  -            if (isAttribute("order"))
  -                id.setOrder(getIntAttribute("order"));
  +			id.setBefore(getAttribute("before"));
  +			id.setAfter(getAttribute("after"));
   
               sd.addInterceptor(id);
   
  
  
  
  1.11      +14 -1     jakarta-hivemind/framework/src/test/hivemind/test/TestMisc.java
  
  Index: TestMisc.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/TestMisc.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- TestMisc.java	28 Feb 2004 00:34:37 -0000	1.10
  +++ TestMisc.java	18 Apr 2004 17:39:58 -0000	1.11
  @@ -201,4 +201,17 @@
   
           assertEquals(System.getProperty("user.home"), s.valueForSymbol("user.home"));
       }
  +
  +    public void testCheckNullParameter()
  +    {
  +        try
  +        {
  +            HiveMind.checkNullParameter("someParameter", null);
  +            unreachable();
  +        }
  +        catch (IllegalArgumentException ex)
  +        {
  +            assertEquals("Parameter someParameter may not be null.", ex.getMessage());
  +        }
  +    }
   }
  
  
  
  1.4       +8 -2      jakarta-hivemind/framework/src/test/hivemind/test/services/impl/TrackerFactory.java
  
  Index: TrackerFactory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/services/impl/TrackerFactory.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- TrackerFactory.java	26 Feb 2004 23:07:35 -0000	1.3
  +++ TrackerFactory.java	18 Apr 2004 17:39:58 -0000	1.4
  @@ -23,6 +23,7 @@
   import org.apache.hivemind.InterceptorStack;
   import org.apache.hivemind.Module;
   import org.apache.hivemind.ServiceInterceptorFactory;
  +import org.apache.hivemind.service.ClassFabUtils;
   
   /**
    * Used with the unit tests.
  @@ -47,7 +48,12 @@
   
           public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
           {
  -            _list.add(_name + ":" + method.getName());
  +        	// For some reason, testing inside Eclipse, logging is getting turned
  +        	// on and toString() is getting invoked ... doesn't happen using
  +        	// command-line testing, though.  A mystery.
  +        	
  +            if (!ClassFabUtils.isToString(method))
  +            	_list.add(_name + ":" + method.getName());
   
               return method.invoke(_inner, args);
           }
  
  
  
  1.8       +3 -3      jakarta-hivemind/framework/src/test/hivemind/test/parse/TestDescriptorParser.java
  
  Index: TestDescriptorParser.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/parse/TestDescriptorParser.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- TestDescriptorParser.java	26 Feb 2004 23:07:50 -0000	1.7
  +++ TestDescriptorParser.java	18 Apr 2004 17:39:58 -0000	1.8
  @@ -176,11 +176,11 @@
   
           InterceptorDescriptor id = (InterceptorDescriptor) l.get(0);
           assertEquals("MyInterceptor", id.getFactoryServiceId());
  -        assertEquals(1000, id.getOrder());
  +        assertEquals("OtherInterceptor", id.getBefore());
   
           id = (InterceptorDescriptor) l.get(1);
           assertEquals("OtherInterceptor", id.getFactoryServiceId());
  -        assertEquals(0, id.getOrder());
  +        assertEquals("MyInterceptor", id.getAfter());
       }
   
       public void testImplementation() throws Exception
  
  
  
  1.4       +3 -3      jakarta-hivemind/framework/src/test/hivemind/test/parse/GenericModule.xml
  
  Index: GenericModule.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/parse/GenericModule.xml,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- GenericModule.xml	26 Feb 2004 23:07:50 -0000	1.3
  +++ GenericModule.xml	18 Apr 2004 17:39:58 -0000	1.4
  @@ -86,8 +86,8 @@
     		
     		<create-instance class="package.impl.MyServiceImpl"/>
     		
  -  		<interceptor service-id="MyInterceptor" order="1000"/>
  -  		<interceptor service-id="OtherInterceptor"/>
  +  		<interceptor service-id="MyInterceptor" before="OtherInterceptor"/>
  +  		<interceptor service-id="OtherInterceptor" after="MyInterceptor"/>
     		
     </service-point>
     
  
  
  
  1.4       +2 -2      jakarta-hivemind/framework/src/test/hivemind/test/parse/BadElement.xml
  
  Index: BadElement.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/parse/BadElement.xml,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- BadElement.xml	26 Feb 2004 23:07:50 -0000	1.3
  +++ BadElement.xml	18 Apr 2004 17:39:58 -0000	1.4
  @@ -86,7 +86,7 @@
     		
     		<create-instance class="package.impl.MyServiceImpl"/>
     		
  -  		<interceptor service-id="MyInterceptor" order="1000"/>
  +  		<interceptor service-id="MyInterceptor"/>
     		<interceptor service-id="OtherInterceptor"/>
     		
     </service-point>
  
  
  
  1.3       +52 -41    jakarta-hivemind/xdocs/images/InterceptorStack.png
  
  	<<Binary file>>
  
  
  1.34      +31 -16    jakarta-hivemind/xdocs/services.xml
  
  Index: services.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/xdocs/services.xml,v
  retrieving revision 1.33
  retrieving revision 1.34
  diff -u -r1.33 -r1.34
  --- services.xml	7 Apr 2004 20:03:28 -0000	1.33
  +++ services.xml	18 Apr 2004 17:39:58 -0000	1.34
  @@ -77,7 +77,9 @@
   			</p>
   			
   			<p>
  -			HiveMind uses a system of <em>proxies</em> for most of the service models. Proxies
  +			HiveMind uses a system of <em>proxies</em> for most of the service models (all except the primitive 
  +			service model, which primarily exists to bootstrap the core HiveMind services
  +			used by other services). Proxies
   			are objects that implement the service interface and take care of details such as constructing
   			the actual implementation of a service on the fly. These lifecycle issues are kept hidden
   			from your code behind the proxies.
  @@ -203,23 +205,36 @@
   					
   				<p>A service extension point may have any number of interceptor
   					contributions. If the order in which interceptors are applied is
  -					important, then the optional order attribute can be specified; it is
  -					used to sort the interceptors into the order in which they will be
  -					applied.</p>
  +					important, then the optional <code>before</code> 
  +					and <code>after</code> attributes can be specified.			
  +					
  +					</p>
   					
   				<img src="images/InterceptorStack.png"/>
   				
  -				<p>
  -				The lowest order ("Security", with an order of 100) is applied first, wrapping around
  -				the core implementation.  Then comes "Performance" and last "Logging".  When a client
  -				invokes a method, it is really invoking it on the "Logging" interceptor, which then re-invokes the method
  -				on the "Performance" interceptor, and so in, down to the core implementation.  Each interceptor
  -				can perjakarta-hivemindform work before and/or after re-invoking the method on the next layer
  -				(as well as catch exceptions thrown by the more inner objects).  In this example,
  -				"Logging" was given a high order so that it wouldn't affect the "Performance" interceptor.  Security
  -				was given a lower order than "Performance" so that the time for security checks would be included in the
  -				"Performance" analysis.
  -				</p>
  +<p>
  +In this example, is was desired that any method logging occur first, before the other
  +interceptors.  This ensures that the time taken to log method entry and exit is not
  +included in the performance statistics (gathered by the performance interceptor).
  +To ensure that the logging interceptor is the first, or earliest, interceptor, the special value
  +<code>*</code>	(rather than a list of interceptor service ids) is given for its <code>before</code>
  +attribute (within the &interceptor; element). This forces the logging interceptor to the front of the list
  +(however, only a single interceptor may be so designated).
  +</p>
  +
  +<p>
  +Likewise, the security checks should occur last, after logging and after performance; this is accomplished
  +by setting the <cde>after</cde>	 attribute to <code>*</code>.  The performance interceptor naturally falls 
  +between the two.
  +</p>
  +
  +<p>
  +This is about as complex as an interceptor stack is likely to grow.  However, through the use of explicit 
  +dependencies, almost any arraingment of interceptors is possible ... even when different modules contribute
  +the interceptors.	
  +</p>
  +
  +
   				
   				<p>
   				Interceptors implement the <code>toString()</code>	method to provide a useful identification for the interceptor,
  
  
  
  1.35      +31 -5     jakarta-hivemind/xdocs/descriptor.xml
  
  Index: descriptor.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/xdocs/descriptor.xml,v
  retrieving revision 1.34
  retrieving revision 1.35
  diff -u -r1.34 -r1.35
  --- descriptor.xml	15 Apr 2004 03:40:34 -0000	1.34
  +++ descriptor.xml	18 Apr 2004 17:39:58 -0000	1.35
  @@ -329,11 +329,18 @@
   						within the same module, or a fully qualified id. </td>
   				</tr>
   				<tr>
  -					<td>order</td>
  -					<td>number</td>
  +					<td>before</td>
  +					<td>string</td>
   					<td>no</td>
  -					<td>A numeric value used to set the order in which interceptors are
  -						applied. Lowest orders go first; the default value is 0.</td>
  +					<td>A list of interceptors whose behavior should come later in execution
  +						than this interceptor.</td>
  +				</tr>
  +								<tr>
  +					<td>after</td>
  +					<td>string</td>
  +					<td>no</td>
  +					<td>A list of interceptors whose behavior should come earlier in execution
  +						than this interceptor.</td>
   				</tr>
   			</table>
   		
  @@ -342,6 +349,25 @@
   As with &invoke-factory;, parameters to the interceptor factory are enclosed by
   the &_interceptor; element. The service interceptor factory will decode the
   parameters using its &parameters-schema; schema definition.
  +</p>
  +
  +<p>
  +Interceptor ordering is based on dependencies; each interceptor can identify, by interceptor service id,
  +other interceptors.  Interceptors in the <code>before</code> list are deferred until after this interceptor.
  +Likewise, this interceptor is deferred until after all interceptors in the <code>after</code> list.
  +</p>
  +
  +<blockquote>
  +	The <code>after</code>	 dependencies will look familar to anyone who has used
  +	<a href="http://ant.apache.org/">Ant</a> or any version of Make.  <code>before</code> dependencies
  +	are simply the opposite.
  +</blockquote>
  +
  +<p>
  +The value for <code>before</code>	 or <code>after</code> is a list of service ids seperated by commas.
  +Service ids may be unqualified if they are within the same module. Alternately, the fixed value
  +<code>*</code> may be used instead of a list: this indicates that the interceptor should be ordered
  +absolutely first or absolutely last.
   </p>
   
   		</section>
  
  
  
  1.3       +85 -84    jakarta-hivemind/src/images/InterceptorStack.psp
  
  	<<Binary file>>
  
  
  1.25      +7 -3      jakarta-hivemind/src/xsl/hivemind.xsl
  
  Index: hivemind.xsl
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/src/xsl/hivemind.xsl,v
  retrieving revision 1.24
  retrieving revision 1.25
  diff -u -r1.24 -r1.25
  --- hivemind.xsl	7 Apr 2004 20:04:05 -0000	1.24
  +++ hivemind.xsl	18 Apr 2004 17:39:58 -0000	1.25
  @@ -484,9 +484,13 @@
   			<span class="tag">&lt;interceptor</span>
   			<span class="attribute"> service-id</span>="<xsl:apply-templates select="/registry/module/service-point[@id = current()/@service-id]" mode="link"/>"
   				
  -			<xsl:if test="@order">
  -			  <span	class="attribute"> order</span>="<xsl:value-of select="@order"/>"
  +			<xsl:if test="@before">
  +			  <span	class="attribute"> before</span>="<xsl:value-of select="@before"/>"
   			</xsl:if> 
  +			
  +			<xsl:if test="@after">
  +			  <span	class="attribute"> after</span>="<xsl:value-of select="@after"/>"
  +			</xsl:if> 			
   
   		  <xsl:choose>
   		  	<xsl:when test="*">
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: hivemind-cvs-unsubscribe@jakarta.apache.org
For additional commands, e-mail: hivemind-cvs-help@jakarta.apache.org


Mime
View raw message