| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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.coyote.ajp; |
| |
| import java.net.InetAddress; |
| import java.net.URLEncoder; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| |
| import javax.management.MBeanRegistration; |
| import javax.management.MBeanServer; |
| import javax.management.ObjectName; |
| |
| import org.apache.commons.modeler.Registry; |
| import org.apache.coyote.ActionCode; |
| import org.apache.coyote.ActionHook; |
| import org.apache.coyote.Adapter; |
| import org.apache.coyote.ProtocolHandler; |
| import org.apache.coyote.RequestGroupInfo; |
| import org.apache.coyote.RequestInfo; |
| import org.apache.tomcat.util.net.AprEndpoint; |
| import org.apache.tomcat.util.net.AprEndpoint.Handler; |
| import org.apache.tomcat.util.res.StringManager; |
| |
| |
| /** |
| * Abstract the protocol implementation, including threading, etc. |
| * Processor is single threaded and specific to stream-based protocols, |
| * will not fit Jk protocols like JNI. |
| * |
| * @author Remy Maucherat |
| * @author Costin Manolache |
| */ |
| public class AjpAprProtocol |
| implements ProtocolHandler, MBeanRegistration { |
| |
| |
| protected static org.apache.commons.logging.Log log = |
| org.apache.commons.logging.LogFactory.getLog(AjpAprProtocol.class); |
| |
| /** |
| * The string manager for this package. |
| */ |
| protected static StringManager sm = |
| StringManager.getManager(Constants.Package); |
| |
| |
| // ------------------------------------------------------------ Constructor |
| |
| |
| public AjpAprProtocol() { |
| cHandler = new AjpConnectionHandler(this); |
| setSoLinger(Constants.DEFAULT_CONNECTION_LINGER); |
| setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT); |
| //setServerSoTimeout(Constants.DEFAULT_SERVER_SOCKET_TIMEOUT); |
| setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY); |
| } |
| |
| |
| // ----------------------------------------------------- Instance Variables |
| |
| |
| protected ObjectName tpOname; |
| |
| |
| protected ObjectName rgOname; |
| |
| |
| /** |
| * Associated APR endpoint. |
| */ |
| protected AprEndpoint ep = new AprEndpoint(); |
| |
| |
| /** |
| * Configuration attributes. |
| */ |
| protected Hashtable attributes = new Hashtable(); |
| |
| |
| /** |
| * Should authentication be done in the native webserver layer, |
| * or in the Servlet container ? |
| */ |
| protected boolean tomcatAuthentication = true; |
| |
| |
| /** |
| * Required secret. |
| */ |
| protected String requiredSecret = null; |
| |
| |
| /** |
| * AJP packet size. |
| */ |
| protected int packetSize = Constants.MAX_PACKET_SIZE; |
| |
| |
| /** |
| * Adapter which will process the requests recieved by this endpoint. |
| */ |
| private Adapter adapter; |
| |
| |
| /** |
| * Connection handler for AJP. |
| */ |
| private AjpConnectionHandler cHandler; |
| |
| |
| // --------------------------------------------------------- Public Methods |
| |
| |
| /** |
| * Pass config info |
| */ |
| public void setAttribute(String name, Object value) { |
| if (log.isTraceEnabled()) { |
| log.trace(sm.getString("ajpprotocol.setattribute", name, value)); |
| } |
| attributes.put(name, value); |
| } |
| |
| public Object getAttribute(String key) { |
| if (log.isTraceEnabled()) { |
| log.trace(sm.getString("ajpprotocol.getattribute", key)); |
| } |
| return attributes.get(key); |
| } |
| |
| |
| public Iterator getAttributeNames() { |
| return attributes.keySet().iterator(); |
| } |
| |
| |
| /** |
| * Set a property. |
| */ |
| public void setProperty(String name, String value) { |
| setAttribute(name, value); |
| } |
| |
| |
| /** |
| * Get a property |
| */ |
| public String getProperty(String name) { |
| return (String) getAttribute(name); |
| } |
| |
| |
| /** |
| * The adapter, used to call the connector |
| */ |
| public void setAdapter(Adapter adapter) { |
| this.adapter = adapter; |
| } |
| |
| |
| public Adapter getAdapter() { |
| return adapter; |
| } |
| |
| |
| /** Start the protocol |
| */ |
| public void init() throws Exception { |
| ep.setName(getName()); |
| ep.setHandler(cHandler); |
| ep.setUseSendfile(false); |
| |
| try { |
| ep.init(); |
| } catch (Exception ex) { |
| log.error(sm.getString("ajpprotocol.endpoint.initerror"), ex); |
| throw ex; |
| } |
| if (log.isInfoEnabled()) { |
| log.info(sm.getString("ajpprotocol.init", getName())); |
| } |
| } |
| |
| |
| public void start() throws Exception { |
| if (this.domain != null ) { |
| try { |
| tpOname = new ObjectName |
| (domain + ":" + "type=ThreadPool,name=" + getName()); |
| Registry.getRegistry(null, null) |
| .registerComponent(ep, tpOname, null ); |
| } catch (Exception e) { |
| log.error("Can't register threadpool" ); |
| } |
| rgOname = new ObjectName |
| (domain + ":type=GlobalRequestProcessor,name=" + getName()); |
| Registry.getRegistry(null, null).registerComponent |
| (cHandler.global, rgOname, null); |
| } |
| |
| try { |
| ep.start(); |
| } catch (Exception ex) { |
| log.error(sm.getString("ajpprotocol.endpoint.starterror"), ex); |
| throw ex; |
| } |
| if (log.isInfoEnabled()) |
| log.info(sm.getString("ajpprotocol.start", getName())); |
| } |
| |
| public void pause() throws Exception { |
| try { |
| ep.pause(); |
| } catch (Exception ex) { |
| log.error(sm.getString("ajpprotocol.endpoint.pauseerror"), ex); |
| throw ex; |
| } |
| if (log.isInfoEnabled()) |
| log.info(sm.getString("ajpprotocol.pause", getName())); |
| } |
| |
| public void resume() throws Exception { |
| try { |
| ep.resume(); |
| } catch (Exception ex) { |
| log.error(sm.getString("ajpprotocol.endpoint.resumeerror"), ex); |
| throw ex; |
| } |
| if (log.isInfoEnabled()) |
| log.info(sm.getString("ajpprotocol.resume", getName())); |
| } |
| |
| public void destroy() throws Exception { |
| if (log.isInfoEnabled()) |
| log.info(sm.getString("ajpprotocol.stop", getName())); |
| ep.destroy(); |
| if (tpOname!=null) |
| Registry.getRegistry(null, null).unregisterComponent(tpOname); |
| if (rgOname != null) |
| Registry.getRegistry(null, null).unregisterComponent(rgOname); |
| } |
| |
| |
| public int getMaxThreads() { |
| return ep.getMaxThreads(); |
| } |
| |
| public void setMaxThreads(int maxThreads) { |
| ep.setMaxThreads(maxThreads); |
| setAttribute("maxThreads", "" + maxThreads); |
| } |
| |
| public void setThreadPriority(int threadPriority) { |
| ep.setThreadPriority(threadPriority); |
| setAttribute("threadPriority", "" + threadPriority); |
| } |
| |
| public int getThreadPriority() { |
| return ep.getThreadPriority(); |
| } |
| |
| |
| public int getBacklog() { |
| return ep.getBacklog(); |
| } |
| |
| |
| public void setBacklog( int i ) { |
| ep.setBacklog(i); |
| setAttribute("backlog", "" + i); |
| } |
| |
| |
| public int getPort() { |
| return ep.getPort(); |
| } |
| |
| |
| public void setPort( int port ) { |
| ep.setPort(port); |
| setAttribute("port", "" + port); |
| } |
| |
| |
| public boolean getUseSendfile() { |
| return ep.getUseSendfile(); |
| } |
| |
| |
| public void setUseSendfile(boolean useSendfile) { |
| // No sendfile for AJP |
| } |
| |
| |
| public InetAddress getAddress() { |
| return ep.getAddress(); |
| } |
| |
| |
| public void setAddress(InetAddress ia) { |
| ep.setAddress(ia); |
| setAttribute("address", "" + ia); |
| } |
| |
| |
| public String getName() { |
| String encodedAddr = ""; |
| if (getAddress() != null) { |
| encodedAddr = "" + getAddress(); |
| if (encodedAddr.startsWith("/")) |
| encodedAddr = encodedAddr.substring(1); |
| encodedAddr = URLEncoder.encode(encodedAddr) + "-"; |
| } |
| return ("ajp-" + encodedAddr + ep.getPort()); |
| } |
| |
| |
| public boolean getTcpNoDelay() { |
| return ep.getTcpNoDelay(); |
| } |
| |
| |
| public void setTcpNoDelay(boolean b) { |
| ep.setTcpNoDelay(b); |
| setAttribute("tcpNoDelay", "" + b); |
| } |
| |
| |
| public boolean getTomcatAuthentication() { |
| return tomcatAuthentication; |
| } |
| |
| |
| public void setTomcatAuthentication(boolean tomcatAuthentication) { |
| this.tomcatAuthentication = tomcatAuthentication; |
| } |
| |
| |
| public int getFirstReadTimeout() { |
| return ep.getFirstReadTimeout(); |
| } |
| |
| |
| public void setFirstReadTimeout(int i) { |
| ep.setFirstReadTimeout(i); |
| setAttribute("firstReadTimeout", "" + i); |
| } |
| |
| |
| public int getPollTime() { |
| return ep.getPollTime(); |
| } |
| |
| |
| public void setPollTime(int i) { |
| ep.setPollTime(i); |
| setAttribute("pollTime", "" + i); |
| } |
| |
| |
| public void setPollerSize(int i) { |
| ep.setPollerSize(i); |
| setAttribute("pollerSize", "" + i); |
| } |
| |
| |
| public int getPollerSize() { |
| return ep.getPollerSize(); |
| } |
| |
| |
| public int getSoLinger() { |
| return ep.getSoLinger(); |
| } |
| |
| |
| public void setSoLinger(int i) { |
| ep.setSoLinger(i); |
| setAttribute("soLinger", "" + i); |
| } |
| |
| |
| public int getSoTimeout() { |
| return ep.getSoTimeout(); |
| } |
| |
| |
| public void setSoTimeout( int i ) { |
| ep.setSoTimeout(i); |
| setAttribute("soTimeout", "" + i); |
| } |
| |
| |
| public void setRequiredSecret(String requiredSecret) { |
| this.requiredSecret = requiredSecret; |
| } |
| |
| |
| public int getPacketSize() { |
| return packetSize; |
| } |
| |
| |
| public void setPacketSize(int packetSize) { |
| if(packetSize <Constants.MAX_PACKET_SIZE) { |
| packetSize = Constants.MAX_PACKET_SIZE; |
| } |
| this.packetSize = packetSize; |
| } |
| |
| |
| // -------------------------------------- AjpConnectionHandler Inner Class |
| |
| |
| protected static class AjpConnectionHandler implements Handler { |
| protected AjpAprProtocol proto; |
| protected static int count = 0; |
| protected RequestGroupInfo global=new RequestGroupInfo(); |
| protected ThreadLocal localProcessor = new ThreadLocal(); |
| |
| public AjpConnectionHandler(AjpAprProtocol proto) { |
| this.proto = proto; |
| } |
| |
| public boolean process(long socket) { |
| AjpAprProcessor processor = null; |
| try { |
| processor = (AjpAprProcessor) localProcessor.get(); |
| if (processor == null) { |
| processor = new AjpAprProcessor(proto.packetSize,proto.ep); |
| processor.setAdapter(proto.adapter); |
| processor.setTomcatAuthentication(proto.tomcatAuthentication); |
| processor.setRequiredSecret(proto.requiredSecret); |
| localProcessor.set(processor); |
| if (proto.getDomain() != null) { |
| synchronized (this) { |
| try { |
| RequestInfo rp = processor.getRequest().getRequestProcessor(); |
| rp.setGlobalProcessor(global); |
| ObjectName rpName = new ObjectName |
| (proto.getDomain() + ":type=RequestProcessor,worker=" |
| + proto.getName() + ",name=AjpRequest" + count++ ); |
| Registry.getRegistry(null, null) |
| .registerComponent(rp, rpName, null); |
| } catch (Exception ex) { |
| log.warn(sm.getString("ajpprotocol.request.register")); |
| } |
| } |
| } |
| } |
| |
| if (processor instanceof ActionHook) { |
| ((ActionHook) processor).action(ActionCode.ACTION_START, null); |
| } |
| |
| return processor.process(socket); |
| |
| } catch(java.net.SocketException e) { |
| // SocketExceptions are normal |
| AjpAprProtocol.log.debug |
| (sm.getString |
| ("ajpprotocol.proto.socketexception.debug"), e); |
| } catch (java.io.IOException e) { |
| // IOExceptions are normal |
| AjpAprProtocol.log.debug |
| (sm.getString |
| ("ajpprotocol.proto.ioexception.debug"), e); |
| } |
| // Future developers: if you discover any other |
| // rare-but-nonfatal exceptions, catch them here, and log as |
| // above. |
| catch (Throwable e) { |
| // any other exception or error is odd. Here we log it |
| // with "ERROR" level, so it will show up even on |
| // less-than-verbose logs. |
| AjpAprProtocol.log.error |
| (sm.getString("ajpprotocol.proto.error"), e); |
| } finally { |
| if (processor instanceof ActionHook) { |
| ((ActionHook) processor).action(ActionCode.ACTION_STOP, null); |
| } |
| } |
| return false; |
| } |
| } |
| |
| |
| // -------------------- Various implementation classes -------------------- |
| |
| |
| protected String domain; |
| protected ObjectName oname; |
| protected MBeanServer mserver; |
| |
| public ObjectName getObjectName() { |
| return oname; |
| } |
| |
| public String getDomain() { |
| return domain; |
| } |
| |
| public ObjectName preRegister(MBeanServer server, |
| ObjectName name) throws Exception { |
| oname=name; |
| mserver=server; |
| domain=name.getDomain(); |
| return name; |
| } |
| |
| public void postRegister(Boolean registrationDone) { |
| } |
| |
| public void preDeregister() throws Exception { |
| } |
| |
| public void postDeregister() { |
| } |
| |
| |
| } |