Return-Path: Delivered-To: apmail-jakarta-avalon-cvs-archive@apache.org Received: (qmail 18691 invoked from network); 7 Nov 2002 09:51:01 -0000 Received: from unknown (HELO nagoya.betaversion.org) (192.18.49.131) by daedalus.apache.org with SMTP; 7 Nov 2002 09:51:01 -0000 Received: (qmail 7960 invoked by uid 97); 7 Nov 2002 09:52:05 -0000 Delivered-To: qmlist-jakarta-archive-avalon-cvs@jakarta.apache.org Received: (qmail 7922 invoked by uid 97); 7 Nov 2002 09:52:04 -0000 Mailing-List: contact avalon-cvs-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "Avalon CVS List" Reply-To: "Avalon Developers List" Delivered-To: mailing list avalon-cvs@jakarta.apache.org Received: (qmail 7906 invoked by uid 97); 7 Nov 2002 09:52:04 -0000 X-Antivirus: nagoya (v4218 created Aug 14 2002) Date: 7 Nov 2002 09:50:41 -0000 Message-ID: <20021107095041.48972.qmail@icarus.apache.org> From: leif@apache.org To: jakarta-avalon-excalibur-cvs@apache.org Subject: cvs commit: jakarta-avalon-excalibur/component/src/java/org/apache/avalon/excalibur/component/servlet AbstractServiceManagerServlet.java ServiceManagerReferenceProxy.java AbstractComponentManagerServlet.java AbstractReferenceProxyLatch.java ComponentManagerReferenceProxy.java ExcaliburComponentManagerServlet.java X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N leif 2002/11/07 01:50:41 Modified: component/src/java/org/apache/avalon/excalibur/component ExcaliburComponentManagerCreator.java component/src/java/org/apache/avalon/excalibur/component/servlet AbstractComponentManagerServlet.java AbstractReferenceProxyLatch.java ComponentManagerReferenceProxy.java ExcaliburComponentManagerServlet.java Added: component/src/java/org/apache/avalon/excalibur/component/servlet AbstractServiceManagerServlet.java ServiceManagerReferenceProxy.java Log: Add access methods for the ServiceManager so that users can easily start moving their code away from using the ComponentManager. Revision Changes Path 1.7 +27 -3 jakarta-avalon-excalibur/component/src/java/org/apache/avalon/excalibur/component/ExcaliburComponentManagerCreator.java Index: ExcaliburComponentManagerCreator.java =================================================================== RCS file: /home/cvs/jakarta-avalon-excalibur/component/src/java/org/apache/avalon/excalibur/component/ExcaliburComponentManagerCreator.java,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- ExcaliburComponentManagerCreator.java 7 Nov 2002 06:37:53 -0000 1.6 +++ ExcaliburComponentManagerCreator.java 7 Nov 2002 09:50:41 -0000 1.7 @@ -22,6 +22,8 @@ import org.apache.avalon.framework.logger.ConsoleLogger; import org.apache.avalon.framework.logger.LogKitLogger; import org.apache.avalon.framework.logger.Logger; +import org.apache.avalon.framework.service.ServiceManager; +import org.apache.excalibur.container.legacy.ComponentManager2ServiceManager; import org.apache.excalibur.instrument.InstrumentManager; import org.apache.excalibur.instrument.manager.DefaultInstrumentManager; import org.apache.log.Hierarchy; @@ -50,8 +52,10 @@ * m_componentManagerCreator = null; * * - * The ComponentManager or any of the other managers can be accessed using their - * getter methods. getComponentManager() for example. + * The ServiceManager (ComponentManager) or any of the other managers can be accessed + * using their getter methods. getServiceManager() for example. Note that + * while the ComponentManager is still available, it has been deprecated in favor + * of the ServiceManager interface. * * @author Leif Mortenson * @version CVS $Revision$ $Date$ @@ -80,6 +84,9 @@ /** Internal component manager. */ private ComponentManager m_componentManager; + /** Internal service manager. */ + private ServiceManager m_serviceManager; + /** Internal instrument manager. */ private InstrumentManager m_instrumentManager; /*--------------------------------------------------------------- @@ -347,6 +354,9 @@ * Returns the configured ComponentManager. * * @return The configured ComponentManager. + * + * @deprecated The ComponentManager interface has been deprecated. + * Please use the getServiceManager method. */ public ComponentManager getComponentManager() { @@ -354,6 +364,16 @@ } /** + * Returns the configured ServiceManager. + * + * @return The configured ServiceManager. + */ + public ServiceManager getServiceManager() + { + return m_serviceManager; + } + + /** * Returns the logger for internal use. */ private Logger getLogger() @@ -468,6 +488,10 @@ componentManager.configure( componentManagerConfig ); componentManager.initialize(); m_componentManager = componentManager; + + // Now wrap the ComponentManager so that we can provide access to it as + // a ServiceManager. + m_serviceManager = new ComponentManager2ServiceManager( m_componentManager ); } } 1.6 +5 -2 jakarta-avalon-excalibur/component/src/java/org/apache/avalon/excalibur/component/servlet/AbstractComponentManagerServlet.java Index: AbstractComponentManagerServlet.java =================================================================== RCS file: /home/cvs/jakarta-avalon-excalibur/component/src/java/org/apache/avalon/excalibur/component/servlet/AbstractComponentManagerServlet.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- AbstractComponentManagerServlet.java 7 Nov 2002 06:37:53 -0000 1.5 +++ AbstractComponentManagerServlet.java 7 Nov 2002 09:50:41 -0000 1.6 @@ -29,6 +29,10 @@ * to enable servlets to have access to a ComponentManager as well as logging * and instrumentation features. * + * @deprecated Use of this class has been deprecated along with the + * ComponentManager interface. Please use the + * AbstractServiceManagerServlet. + * * @author Leif Mortenson * @version CVS $Revision$ $Date$ * @since 4.2 @@ -159,7 +163,6 @@ getLogger().debug( "servlet.destroy()" ); } - //System.out.println( "AbstractComponentManagerServlet.destroy()" ); // Release the ComponentManager by removing its reference. m_componentManager = null; 1.5 +6 -1 jakarta-avalon-excalibur/component/src/java/org/apache/avalon/excalibur/component/servlet/AbstractReferenceProxyLatch.java Index: AbstractReferenceProxyLatch.java =================================================================== RCS file: /home/cvs/jakarta-avalon-excalibur/component/src/java/org/apache/avalon/excalibur/component/servlet/AbstractReferenceProxyLatch.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- AbstractReferenceProxyLatch.java 7 Nov 2002 06:37:53 -0000 1.4 +++ AbstractReferenceProxyLatch.java 7 Nov 2002 09:50:41 -0000 1.5 @@ -10,6 +10,7 @@ import org.apache.avalon.excalibur.logger.LoggerManager; import org.apache.avalon.framework.component.ComponentManager; import org.apache.avalon.framework.logger.AbstractLogEnabled; +import org.apache.avalon.framework.service.ServiceManager; import org.apache.excalibur.instrument.InstrumentManager; /** @@ -73,6 +74,10 @@ if( object instanceof LoggerManager ) { proxy = new LoggerManagerReferenceProxy( (LoggerManager)object, this, name ); + } + else if( object instanceof ServiceManager ) + { + proxy = new ServiceManagerReferenceProxy( (ServiceManager)object, this, name ); } else if( object instanceof ComponentManager ) { 1.3 +4 -1 jakarta-avalon-excalibur/component/src/java/org/apache/avalon/excalibur/component/servlet/ComponentManagerReferenceProxy.java Index: ComponentManagerReferenceProxy.java =================================================================== RCS file: /home/cvs/jakarta-avalon-excalibur/component/src/java/org/apache/avalon/excalibur/component/servlet/ComponentManagerReferenceProxy.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- ComponentManagerReferenceProxy.java 21 Aug 2002 12:45:11 -0000 1.2 +++ ComponentManagerReferenceProxy.java 7 Nov 2002 09:50:41 -0000 1.3 @@ -14,6 +14,9 @@ /** * Reference Proxy to a ComponentManager * + * @deprecated The ComponentManager interface has been deprecated in favor + * of the ServiceManager. + * * @author Leif Mortenson * @version CVS $Revision$ $Date$ * @since 4.2 1.6 +17 -8 jakarta-avalon-excalibur/component/src/java/org/apache/avalon/excalibur/component/servlet/ExcaliburComponentManagerServlet.java Index: ExcaliburComponentManagerServlet.java =================================================================== RCS file: /home/cvs/jakarta-avalon-excalibur/component/src/java/org/apache/avalon/excalibur/component/servlet/ExcaliburComponentManagerServlet.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- ExcaliburComponentManagerServlet.java 7 Nov 2002 06:37:53 -0000 1.5 +++ ExcaliburComponentManagerServlet.java 7 Nov 2002 09:50:41 -0000 1.6 @@ -20,12 +20,13 @@ import org.apache.avalon.excalibur.logger.LoggerManager; import org.apache.avalon.framework.component.ComponentManager; import org.apache.avalon.framework.container.ContainerUtil; +import org.apache.avalon.framework.service.ServiceManager; import org.apache.excalibur.instrument.InstrumentManager; /** * Makes it possible for servlets to work with Avalon components * without having to do any coding to setup and manage the - * lifecycle of the ComponentManager. + * lifecycle of the ServiceManager (ComponentManager). *

* To make use of the ExcaliburComponentManagerServet. You will * need to define the servlet in your web.xml file as follows: @@ -73,7 +74,7 @@ * Please pay particular attention to the load-on-startup element. It is used * to control the order in which servlets are started by the servlet engine. * It must have a value which is less than any other servlets making use of - * the ComponentManager. This is to ensure that the ComponentManager is + * the ServiceManager. This is to ensure that the ServiceManager is * initialized before any other servlets attempt to start using it. *

* All of the configuration files are located in the WEB-INF directory by @@ -84,8 +85,8 @@ * by this servlet, so there is no need to access the class directly. *

* Once the servlet has been configured, other servlets may gain access to - * the ComponentManager, InstrumentManager and LoggerManager via the - * ServletContext using the following code within a servlet: + * the ServiceManager (ComponentManager), InstrumentManager and LoggerManager + * via the ServletContext using the following code within a servlet: *

    *  // Get a reference to the ServletContext
    *  ServletContext servletContext = getServletContext();
  @@ -98,7 +99,11 @@
    *  InstrumentManager instrumentManager =
    *      (InstrumentManager)m_servletContext.getAttribute( InstrumentManager.class.getName() );
    *
  - *  // Acquire the ComponentManager
  + *  // Acquire the ServiceManager
  + *  ServiceManager serviceManager =
  + *      (ServiceManager)m_servletContext.getAttribute( ServiceManager.class.getName() );
  + *
  + *  // Acquire the ComponentManager ( Deprecated )
    *  ComponentManager componentManager =
    *      (ComponentManager)m_servletContext.getAttribute( ComponentManager.class.getName() );
    * 
@@ -232,6 +237,8 @@ // Create the actual ReferenceProxies. ReferenceProxy loggerManagerProxy = m_latch.createProxy( loggerManager, "LoggerManager" ); + ReferenceProxy serviceManagerProxy = m_latch.createProxy( + m_componentManagerCreator.getServiceManager(), "ServiceManager" ); ReferenceProxy componentManagerProxy = m_latch.createProxy( m_componentManagerCreator.getComponentManager(), "ComponentManager" ); ReferenceProxy instrumentManagerProxy = m_latch.createProxy( @@ -239,8 +246,9 @@ // Store references to the proxies in the ServletContext so that other servlets can gain // access to them - servletContext.setAttribute( LoggerManager.class.getName(), loggerManagerProxy ); - servletContext.setAttribute( ComponentManager.class.getName(), componentManagerProxy ); + servletContext.setAttribute( LoggerManager.class.getName(), loggerManagerProxy ); + servletContext.setAttribute( ServiceManager.class.getName(), serviceManagerProxy ); + servletContext.setAttribute( ComponentManager.class.getName(), componentManagerProxy ); servletContext.setAttribute( InstrumentManager.class.getName(), instrumentManagerProxy ); //System.out.println( "ExcaliburComponentManagerServlet.init() END" ); @@ -257,6 +265,7 @@ // Remove the references to the managers from the servlet context. servletContext.removeAttribute( LoggerManager.class.getName() ); + servletContext.removeAttribute( ServiceManager.class.getName() ); servletContext.removeAttribute( ComponentManager.class.getName() ); servletContext.removeAttribute( InstrumentManager.class.getName() ); 1.1 jakarta-avalon-excalibur/component/src/java/org/apache/avalon/excalibur/component/servlet/AbstractServiceManagerServlet.java Index: AbstractServiceManagerServlet.java =================================================================== /* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software License * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ package org.apache.avalon.excalibur.component.servlet; import java.io.IOException; import java.util.ArrayList; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.avalon.excalibur.logger.LoggerManager; import org.apache.avalon.framework.service.ServiceManager; import org.apache.avalon.framework.logger.Logger; import org.apache.excalibur.instrument.CounterInstrument; import org.apache.excalibur.instrument.Instrument; import org.apache.excalibur.instrument.Instrumentable; import org.apache.excalibur.instrument.InstrumentManager; import org.apache.excalibur.instrument.ValueInstrument; /** * Abstract Servlet which can be used with the ExcaliburServiceManagerServlet * to enable servlets to have access to a ServiceManager as well as logging * and instrumentation features. * * @author Leif Mortenson * @version CVS $Revision: 1.1 $ $Date: 2002/11/07 09:50:41 $ * @since 4.2 */ public abstract class AbstractServiceManagerServlet extends HttpServlet implements Instrumentable { private String m_referenceName; private ServiceManager m_serviceManager; private Logger m_logger; /** Instrumentable Name assigned to this Instrumentable */ private String m_instrumentableName; /** Stores the instruments during initialization. */ private ArrayList m_instrumentList; /** Stores the child instrumentables during initialization. */ private ArrayList m_childList; /** Flag which is to used to keep track of when the Instrumentable has been registered. */ private boolean m_registered; /** Counts the number of times the service is requested. */ private CounterInstrument m_instrumentRequests; /** Records the amount of time execute takes to be processed. */ private ValueInstrument m_instrumentTime; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Create a new AbstractServiceManagerServlet. * * @param referenceName A name which does not include any spaces or periods * that will be used to name the logger category and * instrumentable which represents this servlet. */ public AbstractServiceManagerServlet( String referenceName ) { //System.out.println( "AbstractServiceManagerServlet( " + referenceName + " )" ); m_referenceName = referenceName; // Set up Instrumentable like AbstractInstrumentable m_registered = false; m_instrumentList = new ArrayList(); m_childList = new ArrayList(); // Create the instruments setInstrumentableName( referenceName ); addInstrument( m_instrumentRequests = new CounterInstrument( "requests" ) ); addInstrument( m_instrumentTime = new ValueInstrument( "time" ) ); } /*--------------------------------------------------------------- * HttpServlet Methods *-------------------------------------------------------------*/ /** * Called by the servlet container to initialize a servlet before it is * put into service. * * @param config ServletConfig object for the servlet. * * @throws ServletException If there are any initialization problems. */ public void init( ServletConfig config ) throws ServletException { ServletContext context = config.getServletContext(); // Initialize logging for the servlet. LoggerManager loggerManager = (LoggerManager)context.getAttribute( LoggerManager.class.getName() ); if ( loggerManager == null ) { throw new IllegalStateException( "The ExcaliburComponentManagerServlet servlet was not correctly initialized." ); } Logger logger = loggerManager.getLoggerForCategory( "servlet" ); m_logger = logger.getChildLogger( m_referenceName ); if ( getLogger().isDebugEnabled() ) { getLogger().debug( "servlet.init( config )" ); } // Obtain a reference to the ServiceManager m_serviceManager = (ServiceManager)context.getAttribute( ServiceManager.class.getName() ); if ( m_serviceManager == null ) { throw new IllegalStateException( "The ExcaliburComponentManagerServlet servlet was not correctly initialized." ); } // Register this servlet with the InstrumentManager if it exists. InstrumentManager instrumentManager = (InstrumentManager)context.getAttribute( InstrumentManager.class.getName() ); if ( instrumentManager != null ) { try { instrumentManager.registerInstrumentable( this, "servlets." + getInstrumentableName() ); } catch ( Exception e ) { throw new ServletException( "Unable to register the servlet with the instrument manager.", e ); } } // Do this last so the subclasses will be able to access these objects in their // init method. super.init( config ); } /** * Called by the servlet container to indicate to a servlet that the servlet * is being taken out of service. */ public void destroy() { if ( getLogger().isDebugEnabled() ) { getLogger().debug( "servlet.destroy()" ); } // Release the ServiceManager by removing its reference. m_serviceManager = null; super.destroy(); // Make sure that the component manager gets collected. System.gc(); // Give the system time for the Gc to complete. This is necessary to make sure that // the ECMServlet has time to dispose all of its managers before the Tomcat server // invalidates the current class loader. try { Thread.sleep(250); } catch ( InterruptedException e ) { } } /** * Receives standard HTTP requests from the public service method and dispatches * them to the doXXX methods defined in this class. * Overrides the default method to allow for instrumentation. * * @param request The HttpServletRequest object that contains the request the * client made of the servlet. * @param response The HttpServletResponse object that contains the response * the servlet returns to the client. */ public void service( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException { if ( getLogger().isDebugEnabled() ) { StringBuffer sb = new StringBuffer( request.getRequestURI() ); String query = request.getQueryString(); if ( query != null ) { sb.append( "?" ); sb.append( query ); } getLogger().debug( "Request: " + sb.toString() ); } long start = System.currentTimeMillis(); // Notify the Instrument Manager m_instrumentRequests.increment(); super.service( request, response ); // Notify the Instrument Manager how long the service took. if ( m_instrumentTime.isActive() ) { m_instrumentTime.setValue( (int)( System.currentTimeMillis() - start ) ); } } /*--------------------------------------------------------------- * Instrumentable Methods *-------------------------------------------------------------*/ /** * Gets the name of the Instrumentable. * * @return The name used to identify a Instrumentable. */ public final String getInstrumentableName() { return m_instrumentableName; } /** * Sets the name for the Instrumentable. The Instrumentable Name is used * to uniquely identify the Instrumentable during the configuration of * the InstrumentManager and to gain access to an InstrumentableDescriptor * through the InstrumentManager. The value should be a string which does * not contain spaces or periods. *

* This value may be set by a parent Instrumentable, or by the * InstrumentManager using the value of the 'instrumentable' attribute in * the configuration of the component. * * @param name The name used to identify a Instrumentable. */ public final void setInstrumentableName( String name ) { m_instrumentableName = name; } /** * Any Object which implements Instrumentable can also make use of other * Instrumentable child objects. This method is used to tell the * InstrumentManager about them. * * @return An array of child Instrumentables. This method should never * return null. If there are no child Instrumentables, then * EMPTY_INSTRUMENTABLE_ARRAY can be returned. */ public final Instrumentable[] getChildInstrumentables() { m_registered = true; if( m_childList.size() == 0 ) { return Instrumentable.EMPTY_INSTRUMENTABLE_ARRAY; } else { Instrumentable[] children = new Instrumentable[ m_childList.size() ]; m_childList.toArray( children ); return children; } } /** * Obtain a reference to all the Instruments that the Instrumentable object * wishes to expose. All sampling is done directly through the * Instruments as opposed to the Instrumentable interface. * * @return An array of the Instruments available for profiling. Should * never be null. If there are no Instruments, then * EMPTY_INSTRUMENT_ARRAY can be returned. This should never be * the case though unless there are child Instrumentables with * Instruments. */ public final Instrument[] getInstruments() { m_registered = true; if( m_instrumentList.size() == 0 ) { return Instrumentable.EMPTY_INSTRUMENT_ARRAY; } else { Instrument[] instruments = new Instrument[ m_instrumentList.size() ]; m_instrumentList.toArray( instruments ); return instruments; } } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Adds an Instrument to the list of Instruments published by the component. * This method may not be called after the Instrumentable has been * registered with the InstrumentManager. * * @param instrument Instrument to publish. */ protected void addInstrument( Instrument instrument ) { if( m_registered ) { throw new IllegalStateException( "Instruments can not be added after the " + "Instrumentable is registered with the InstrumentManager." ); } m_instrumentList.add( instrument ); } /** * Adds a child Instrumentable to the list of child Instrumentables * published by the component. This method may not be called after the * Instrumentable has been registered with the InstrumentManager. *

* Note that Child Instrumentables must be named by the caller using the * setInstrumentableName method. * * @param child Child Instrumentable to publish. */ protected void addChildInstrumentable( Instrumentable child ) { if( m_registered ) { throw new IllegalStateException( "Child Instrumentables can not be added after the " + "Instrumentable is registered with the InstrumentManager." ); } m_childList.add( child ); } /** * Obtain a reference to the servlet's logger. * * @return The servlet's logger. */ protected Logger getLogger() { return m_logger; } /** * Returns the current ServiceManager. * * @return The current ServiceManager. */ public ServiceManager getServiceManager() { return m_serviceManager; } } 1.1 jakarta-avalon-excalibur/component/src/java/org/apache/avalon/excalibur/component/servlet/ServiceManagerReferenceProxy.java Index: ServiceManagerReferenceProxy.java =================================================================== /* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software License * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ package org.apache.avalon.excalibur.component.servlet; import org.apache.avalon.framework.service.ServiceException; import org.apache.avalon.framework.service.ServiceManager; /** * Reference Proxy to a ServiceManager * * @author Leif Mortenson * @version CVS $Revision: 1.1 $ $Date: 2002/11/07 09:50:41 $ * @since 4.2 */ final class ServiceManagerReferenceProxy extends AbstractReferenceProxy implements ServiceManager { private ServiceManager m_serviceManager; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Create a new proxy. * * @param serviceManager ServiceManager being proxied. * @param latch Latch wich will be notified when this proxy is finalized. * @param name Name of the proxy. */ ServiceManagerReferenceProxy( ServiceManager serviceManager, AbstractReferenceProxyLatch latch, String name ) { super( latch, name ); m_serviceManager = serviceManager; } /*--------------------------------------------------------------- * ServiceManager Methods *-------------------------------------------------------------*/ /** * Get the Object associated with the given role. For * instance, If the ServiceManager had a * LoggerComponent stored and referenced by role, I would use * the following call: *

       * try
       * {
       *     MyComponent log;
       *     myComponent = (MyComponent) manager.lookup(MyComponent.ROLE);
       * }
       * catch (...)
       * {
       *     ...
       * }
       * 
* * @param role The role name of the Object to retrieve. * @return an Object value * @throws ServiceException if an error occurs */ public Object lookup( String role ) throws ServiceException { return m_serviceManager.lookup( role ); } /** * Check to see if a Object exists for a role. * * @param role a string identifying the role to check. * @return True if the object exists, False if it does not. */ public boolean hasService( String role ) { return m_serviceManager.hasService( role ); } /** * Return the Object when you are finished with it. This * allows the ServiceManager to handle the End-Of-Life Lifecycle * events associated with the Object. Please note, that no * Exception should be thrown at this point. This is to allow easy use of the * ServiceManager system without having to trap Exceptions on a release. * * @param object The Object we are releasing. */ public void release( Object service ) { m_serviceManager.release( service ); } } -- To unsubscribe, e-mail: For additional commands, e-mail: