Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » coyote » ajp » [javadoc | source]
    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one or more
    3    *  contributor license agreements.  See the NOTICE file distributed with
    4    *  this work for additional information regarding copyright ownership.
    5    *  The ASF licenses this file to You under the Apache License, Version 2.0
    6    *  (the "License"); you may not use this file except in compliance with
    7    *  the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    *  Unless required by applicable law or agreed to in writing, software
   12    *  distributed under the License is distributed on an "AS IS" BASIS,
   13    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    *  See the License for the specific language governing permissions and
   15    *  limitations under the License.
   16    */
   17   
   18   package org.apache.coyote.ajp;
   19   
   20   import java.net.InetAddress;
   21   import java.net.URLEncoder;
   22   import java.util.Hashtable;
   23   import java.util.Iterator;
   24   import java.util.concurrent.ConcurrentLinkedQueue;
   25   import java.util.concurrent.Executor;
   26   import java.util.concurrent.atomic.AtomicInteger;
   27   import java.util.concurrent.atomic.AtomicLong;
   28   
   29   import javax.management.MBeanRegistration;
   30   import javax.management.MBeanServer;
   31   import javax.management.ObjectName;
   32   
   33   import org.apache.coyote.ActionCode;
   34   import org.apache.coyote.ActionHook;
   35   import org.apache.coyote.Adapter;
   36   import org.apache.coyote.ProtocolHandler;
   37   import org.apache.coyote.RequestGroupInfo;
   38   import org.apache.coyote.RequestInfo;
   39   import org.apache.tomcat.util.modeler.Registry;
   40   import org.apache.tomcat.util.net.AprEndpoint;
   41   import org.apache.tomcat.util.net.SocketStatus;
   42   import org.apache.tomcat.util.net.AprEndpoint.Handler;
   43   import org.apache.tomcat.util.res.StringManager;
   44   
   45   
   46   /**
   47    * Abstract the protocol implementation, including threading, etc.
   48    * Processor is single threaded and specific to stream-based protocols,
   49    * will not fit Jk protocols like JNI.
   50    *
   51    * @author Remy Maucherat
   52    * @author Costin Manolache
   53    */
   54   public class AjpAprProtocol 
   55       implements ProtocolHandler, MBeanRegistration {
   56       
   57       
   58       protected static org.apache.juli.logging.Log log =
   59           org.apache.juli.logging.LogFactory.getLog(AjpAprProtocol.class);
   60   
   61       /**
   62        * The string manager for this package.
   63        */
   64       protected static StringManager sm =
   65           StringManager.getManager(Constants.Package);
   66   
   67   
   68       // ------------------------------------------------------------ Constructor
   69   
   70   
   71       public AjpAprProtocol() {
   72           cHandler = new AjpConnectionHandler(this);
   73           setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
   74           setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
   75           //setServerSoTimeout(Constants.DEFAULT_SERVER_SOCKET_TIMEOUT);
   76           setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
   77       }
   78   
   79       
   80       // ----------------------------------------------------- Instance Variables
   81   
   82   
   83       protected ObjectName tpOname;
   84       
   85       
   86       protected ObjectName rgOname;
   87   
   88   
   89       /**
   90        * Associated APR endpoint.
   91        */
   92       protected AprEndpoint endpoint = new AprEndpoint();
   93   
   94   
   95       /**
   96        * Configuration attributes.
   97        */
   98       protected Hashtable attributes = new Hashtable();
   99   
  100   
  101       /**
  102        * Adapter which will process the requests recieved by this endpoint.
  103        */
  104       private Adapter adapter;
  105       
  106       
  107       /**
  108        * Connection handler for AJP.
  109        */
  110       private AjpConnectionHandler cHandler;
  111   
  112   
  113       // --------------------------------------------------------- Public Methods
  114   
  115   
  116       /** 
  117        * Pass config info
  118        */
  119       public void setAttribute(String name, Object value) {
  120           if (log.isTraceEnabled()) {
  121               log.trace(sm.getString("ajpprotocol.setattribute", name, value));
  122           }
  123           attributes.put(name, value);
  124       }
  125   
  126       public Object getAttribute(String key) {
  127           if (log.isTraceEnabled()) {
  128               log.trace(sm.getString("ajpprotocol.getattribute", key));
  129           }
  130           return attributes.get(key);
  131       }
  132   
  133   
  134       public Iterator getAttributeNames() {
  135           return attributes.keySet().iterator();
  136       }
  137   
  138   
  139       /**
  140        * The adapter, used to call the connector
  141        */
  142       public void setAdapter(Adapter adapter) {
  143           this.adapter = adapter;
  144       }
  145   
  146   
  147       public Adapter getAdapter() {
  148           return adapter;
  149       }
  150   
  151   
  152       /** Start the protocol
  153        */
  154       public void init() throws Exception {
  155           endpoint.setName(getName());
  156           endpoint.setHandler(cHandler);
  157           endpoint.setUseSendfile(false);
  158   
  159           try {
  160               endpoint.init();
  161           } catch (Exception ex) {
  162               log.error(sm.getString("ajpprotocol.endpoint.initerror"), ex);
  163               throw ex;
  164           }
  165           if (log.isInfoEnabled()) {
  166               log.info(sm.getString("ajpprotocol.init", getName()));
  167           }
  168       }
  169   
  170   
  171       public void start() throws Exception {
  172           if (this.domain != null ) {
  173               try {
  174                   tpOname = new ObjectName
  175                       (domain + ":" + "type=ThreadPool,name=" + getName());
  176                   Registry.getRegistry(null, null)
  177                       .registerComponent(endpoint, tpOname, null );
  178               } catch (Exception e) {
  179                   log.error("Can't register threadpool" );
  180               }
  181               rgOname = new ObjectName
  182                   (domain + ":type=GlobalRequestProcessor,name=" + getName());
  183               Registry.getRegistry(null, null).registerComponent
  184                   (cHandler.global, rgOname, null);
  185           }
  186   
  187           try {
  188               endpoint.start();
  189           } catch (Exception ex) {
  190               log.error(sm.getString("ajpprotocol.endpoint.starterror"), ex);
  191               throw ex;
  192           }
  193           if (log.isInfoEnabled())
  194               log.info(sm.getString("ajpprotocol.start", getName()));
  195       }
  196   
  197       public void pause() throws Exception {
  198           try {
  199               endpoint.pause();
  200           } catch (Exception ex) {
  201               log.error(sm.getString("ajpprotocol.endpoint.pauseerror"), ex);
  202               throw ex;
  203           }
  204           if (log.isInfoEnabled())
  205               log.info(sm.getString("ajpprotocol.pause", getName()));
  206       }
  207   
  208       public void resume() throws Exception {
  209           try {
  210               endpoint.resume();
  211           } catch (Exception ex) {
  212               log.error(sm.getString("ajpprotocol.endpoint.resumeerror"), ex);
  213               throw ex;
  214           }
  215           if (log.isInfoEnabled())
  216               log.info(sm.getString("ajpprotocol.resume", getName()));
  217       }
  218   
  219       public void destroy() throws Exception {
  220           if (log.isInfoEnabled())
  221               log.info(sm.getString("ajpprotocol.stop", getName()));
  222           endpoint.destroy();
  223           if (tpOname!=null)
  224               Registry.getRegistry(null, null).unregisterComponent(tpOname);
  225           if (rgOname != null)
  226               Registry.getRegistry(null, null).unregisterComponent(rgOname);
  227       }
  228   
  229       // *
  230       public String getName() {
  231           String encodedAddr = "";
  232           if (getAddress() != null) {
  233               encodedAddr = "" + getAddress();
  234               if (encodedAddr.startsWith("/"))
  235                   encodedAddr = encodedAddr.substring(1);
  236               encodedAddr = URLEncoder.encode(encodedAddr) + "-";
  237           }
  238           return ("ajp-" + encodedAddr + endpoint.getPort());
  239       }
  240   
  241       /**
  242        * Processor cache.
  243        */
  244       protected int processorCache = -1;
  245       public int getProcessorCache() { return this.processorCache; }
  246       public void setProcessorCache(int processorCache) { this.processorCache = processorCache; }
  247   
  248       public Executor getExecutor() { return endpoint.getExecutor(); }
  249       public void setExecutor(Executor executor) { endpoint.setExecutor(executor); }
  250       
  251       public int getMaxThreads() { return endpoint.getMaxThreads(); }
  252       public void setMaxThreads(int maxThreads) { endpoint.setMaxThreads(maxThreads); }
  253   
  254       public int getThreadPriority() { return endpoint.getThreadPriority(); }
  255       public void setThreadPriority(int threadPriority) { endpoint.setThreadPriority(threadPriority); }
  256   
  257       public int getBacklog() { return endpoint.getBacklog(); }
  258       public void setBacklog(int backlog) { endpoint.setBacklog(backlog); }
  259   
  260       public int getPort() { return endpoint.getPort(); }
  261       public void setPort(int port) { endpoint.setPort(port); }
  262   
  263       public InetAddress getAddress() { return endpoint.getAddress(); }
  264       public void setAddress(InetAddress ia) { endpoint.setAddress(ia); }
  265   
  266       public boolean getTcpNoDelay() { return endpoint.getTcpNoDelay(); }
  267       public void setTcpNoDelay(boolean tcpNoDelay) { endpoint.setTcpNoDelay(tcpNoDelay); }
  268   
  269       public int getSoLinger() { return endpoint.getSoLinger(); }
  270       public void setSoLinger(int soLinger) { endpoint.setSoLinger(soLinger); }
  271   
  272       public int getSoTimeout() { return endpoint.getSoTimeout(); }
  273       public void setSoTimeout(int soTimeout) { endpoint.setSoTimeout(soTimeout); }
  274   
  275       /**
  276        * Should authentication be done in the native webserver layer, 
  277        * or in the Servlet container ?
  278        */
  279       protected boolean tomcatAuthentication = true;
  280       public boolean getTomcatAuthentication() { return tomcatAuthentication; }
  281       public void setTomcatAuthentication(boolean tomcatAuthentication) { this.tomcatAuthentication = tomcatAuthentication; }
  282   
  283       /**
  284        * Required secret.
  285        */
  286       protected String requiredSecret = null;
  287       public void setRequiredSecret(String requiredSecret) { this.requiredSecret = requiredSecret; }
  288       
  289       /**
  290        * AJP packet size.
  291        */
  292       protected int packetSize = Constants.MAX_PACKET_SIZE;
  293       public int getPacketSize() { return packetSize; }
  294       public void setPacketSize(int packetSize) { this.packetSize = packetSize; }
  295   
  296       /**
  297        * The number of seconds Tomcat will wait for a subsequent request
  298        * before closing the connection.
  299        */
  300       public int getKeepAliveTimeout() { return endpoint.getKeepAliveTimeout(); }
  301       public void setKeepAliveTimeout(int timeout) { endpoint.setKeepAliveTimeout(timeout); }
  302   
  303       public boolean getUseSendfile() { return endpoint.getUseSendfile(); }
  304       public void setUseSendfile(boolean useSendfile) { /* No sendfile for AJP */ }
  305   
  306       public int getPollTime() { return endpoint.getPollTime(); }
  307       public void setPollTime(int pollTime) { endpoint.setPollTime(pollTime); }
  308   
  309       public void setPollerSize(int pollerSize) { endpoint.setPollerSize(pollerSize); }
  310       public int getPollerSize() { return endpoint.getPollerSize(); }
  311   
  312       // --------------------------------------  AjpConnectionHandler Inner Class
  313   
  314   
  315       protected static class AjpConnectionHandler implements Handler {
  316   
  317           protected AjpAprProtocol proto;
  318           protected AtomicLong registerCount = new AtomicLong(0);
  319           protected RequestGroupInfo global = new RequestGroupInfo();
  320   
  321           protected ConcurrentLinkedQueue<AjpAprProcessor> recycledProcessors = 
  322               new ConcurrentLinkedQueue<AjpAprProcessor>() {
  323               protected AtomicInteger size = new AtomicInteger(0);
  324               public boolean offer(AjpAprProcessor processor) {
  325                   boolean offer = (proto.processorCache == -1) ? true : (size.get() < proto.processorCache);
  326                   //avoid over growing our cache or add after we have stopped
  327                   boolean result = false;
  328                   if ( offer ) {
  329                       result = super.offer(processor);
  330                       if ( result ) {
  331                           size.incrementAndGet();
  332                       }
  333                   }
  334                   if (!result) unregister(processor);
  335                   return result;
  336               }
  337               
  338               public AjpAprProcessor poll() {
  339                   AjpAprProcessor result = super.poll();
  340                   if ( result != null ) {
  341                       size.decrementAndGet();
  342                   }
  343                   return result;
  344               }
  345               
  346               public void clear() {
  347                   AjpAprProcessor next = poll();
  348                   while ( next != null ) {
  349                       unregister(next);
  350                       next = poll();
  351                   }
  352                   super.clear();
  353                   size.set(0);
  354               }
  355           };
  356   
  357           public AjpConnectionHandler(AjpAprProtocol proto) {
  358               this.proto = proto;
  359           }
  360   
  361           // FIXME: Support for this could be added in AJP as well
  362           public SocketState event(long socket, SocketStatus status) {
  363               return SocketState.CLOSED;
  364           }
  365           
  366           public SocketState process(long socket) {
  367               AjpAprProcessor processor = recycledProcessors.poll();
  368               try {
  369   
  370                   if (processor == null) {
  371                       processor = createProcessor();
  372                   }
  373   
  374                   if (processor instanceof ActionHook) {
  375                       ((ActionHook) processor).action(ActionCode.ACTION_START, null);
  376                   }
  377   
  378                   if (processor.process(socket)) {
  379                       return SocketState.OPEN;
  380                   } else {
  381                       return SocketState.CLOSED;
  382                   }
  383   
  384               } catch(java.net.SocketException e) {
  385                   // SocketExceptions are normal
  386                   AjpAprProtocol.log.debug
  387                       (sm.getString
  388                        ("ajpprotocol.proto.socketexception.debug"), e);
  389               } catch (java.io.IOException e) {
  390                   // IOExceptions are normal
  391                   AjpAprProtocol.log.debug
  392                       (sm.getString
  393                        ("ajpprotocol.proto.ioexception.debug"), e);
  394               }
  395               // Future developers: if you discover any other
  396               // rare-but-nonfatal exceptions, catch them here, and log as
  397               // above.
  398               catch (Throwable e) {
  399                   // any other exception or error is odd. Here we log it
  400                   // with "ERROR" level, so it will show up even on
  401                   // less-than-verbose logs.
  402                   AjpAprProtocol.log.error
  403                       (sm.getString("ajpprotocol.proto.error"), e);
  404               } finally {
  405                   if (processor instanceof ActionHook) {
  406                       ((ActionHook) processor).action(ActionCode.ACTION_STOP, null);
  407                   }
  408                   recycledProcessors.offer(processor);
  409               }
  410               return SocketState.CLOSED;
  411           }
  412   
  413           protected AjpAprProcessor createProcessor() {
  414               AjpAprProcessor processor = new AjpAprProcessor(proto.packetSize, proto.endpoint);
  415               processor.setAdapter(proto.adapter);
  416               processor.setTomcatAuthentication(proto.tomcatAuthentication);
  417               processor.setRequiredSecret(proto.requiredSecret);
  418               register(processor);
  419               return processor;
  420           }
  421           
  422           protected void register(AjpAprProcessor processor) {
  423               if (proto.getDomain() != null) {
  424                   synchronized (this) {
  425                       try {
  426                           long count = registerCount.incrementAndGet();
  427                           RequestInfo rp = processor.getRequest().getRequestProcessor();
  428                           rp.setGlobalProcessor(global);
  429                           ObjectName rpName = new ObjectName
  430                               (proto.getDomain() + ":type=RequestProcessor,worker="
  431                                   + proto.getName() + ",name=AjpRequest" + count);
  432                           if (log.isDebugEnabled()) {
  433                               log.debug("Register " + rpName);
  434                           }
  435                           Registry.getRegistry(null, null).registerComponent(rp, rpName, null);
  436                           rp.setRpName(rpName);
  437                       } catch (Exception e) {
  438                           log.warn("Error registering request");
  439                       }
  440                   }
  441               }
  442           }
  443   
  444           protected void unregister(AjpAprProcessor processor) {
  445               if (proto.getDomain() != null) {
  446                   synchronized (this) {
  447                       try {
  448                           RequestInfo rp = processor.getRequest().getRequestProcessor();
  449                           rp.setGlobalProcessor(null);
  450                           ObjectName rpName = rp.getRpName();
  451                           if (log.isDebugEnabled()) {
  452                               log.debug("Unregister " + rpName);
  453                           }
  454                           Registry.getRegistry(null, null).unregisterComponent(rpName);
  455                           rp.setRpName(null);
  456                       } catch (Exception e) {
  457                           log.warn("Error unregistering request", e);
  458                       }
  459                   }
  460               }
  461           }
  462   
  463       }
  464   
  465   
  466       // -------------------- Various implementation classes --------------------
  467   
  468   
  469       protected String domain;
  470       protected ObjectName oname;
  471       protected MBeanServer mserver;
  472   
  473       public ObjectName getObjectName() {
  474           return oname;
  475       }
  476   
  477       public String getDomain() {
  478           return domain;
  479       }
  480   
  481       public ObjectName preRegister(MBeanServer server,
  482                                     ObjectName name) throws Exception {
  483           oname=name;
  484           mserver=server;
  485           domain=name.getDomain();
  486           return name;
  487       }
  488   
  489       public void postRegister(Boolean registrationDone) {
  490       }
  491   
  492       public void preDeregister() throws Exception {
  493       }
  494   
  495       public void postDeregister() {
  496       }
  497       
  498    
  499   }

Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » coyote » ajp » [javadoc | source]