+++ /dev/null
-/*
- * 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.jk.common;
-
-
-/**
- * Common class for the AJP Protocol values
- */
-
-public class AjpConstants {
- // Prefix codes for message types from server to container
- /**
- * Message code for initial Request packet
- */
- public static final byte JK_AJP13_FORWARD_REQUEST = 2;
- /**
- * Message code for a request to shutdown Tomcat
- */
- public static final byte JK_AJP13_SHUTDOWN = 7;
- /**
- * Message code for a Ping request (obsolete)
- */
- public static final byte JK_AJP13_PING_REQUEST = 8;
- /**
- * Message code for a CPing request
- */
- public static final byte JK_AJP13_CPING_REQUEST = 10;
-
- // Prefix codes for message types from container to server
- /**
- * Response code that the package is part of the Response body
- */
- public static final byte JK_AJP13_SEND_BODY_CHUNK = 3;
- /**
- * Response code that the package is the HTTP headers
- */
- public static final byte JK_AJP13_SEND_HEADERS = 4;
- /**
- * Response code for EOT
- */
- public static final byte JK_AJP13_END_RESPONSE = 5;
- /**
- * Response code to request the next Request body chunk
- */
- public static final byte JK_AJP13_GET_BODY_CHUNK = 6;
- /**
- * Response code to reply to a CPing
- */
- public static final byte JK_AJP13_CPONG_REPLY = 9;
-
- // Integer codes for common response header strings
- public static final int SC_RESP_CONTENT_TYPE = 0xA001;
- public static final int SC_RESP_CONTENT_LANGUAGE = 0xA002;
- public static final int SC_RESP_CONTENT_LENGTH = 0xA003;
- public static final int SC_RESP_DATE = 0xA004;
- public static final int SC_RESP_LAST_MODIFIED = 0xA005;
- public static final int SC_RESP_LOCATION = 0xA006;
- public static final int SC_RESP_SET_COOKIE = 0xA007;
- public static final int SC_RESP_SET_COOKIE2 = 0xA008;
- public static final int SC_RESP_SERVLET_ENGINE = 0xA009;
- public static final int SC_RESP_STATUS = 0xA00A;
- public static final int SC_RESP_WWW_AUTHENTICATE = 0xA00B;
-
- // Integer codes for common (optional) request attribute names
- public static final byte SC_A_CONTEXT = 1; // XXX Unused
- public static final byte SC_A_SERVLET_PATH = 2; // XXX Unused
- public static final byte SC_A_REMOTE_USER = 3;
- public static final byte SC_A_AUTH_TYPE = 4;
- public static final byte SC_A_QUERY_STRING = 5;
- public static final byte SC_A_JVM_ROUTE = 6;
- public static final byte SC_A_SSL_CERT = 7;
- public static final byte SC_A_SSL_CIPHER = 8;
- public static final byte SC_A_SSL_SESSION = 9;
- public static final byte SC_A_SSL_KEYSIZE = 11;
- public static final byte SC_A_SECRET = 12;
- public static final byte SC_A_STORED_METHOD = 13;
-
- // Used for attributes which are not in the list above
- /**
- * Request Attribute is passed as a String
- */
- public static final byte SC_A_REQ_ATTRIBUTE = 10;
-
- /**
- * AJP private request attributes
- */
- public static final String SC_A_REQ_REMOTE_PORT = "AJP_REMOTE_PORT";
-
- /**
- * Terminates list of attributes
- */
- public static final byte SC_A_ARE_DONE = (byte)0xFF;
-
- /**
- * Translates integer codes to names of HTTP methods
- */
- public static final String []methodTransArray = {
- "OPTIONS",
- "GET",
- "HEAD",
- "POST",
- "PUT",
- "DELETE",
- "TRACE",
- "PROPFIND",
- "PROPPATCH",
- "MKCOL",
- "COPY",
- "MOVE",
- "LOCK",
- "UNLOCK",
- "ACL",
- "REPORT",
- "VERSION-CONTROL",
- "CHECKIN",
- "CHECKOUT",
- "UNCHECKOUT",
- "SEARCH",
- "MKWORKSPACE",
- "UPDATE",
- "LABEL",
- "MERGE",
- "BASELINE-CONTROL",
- "MKACTIVITY"
- };
-
- /**
- * Request Method is passed as a String
- */
- public static final int SC_M_JK_STORED = (byte) 0xFF;
-
- // id's for common request headers
- public static final int SC_REQ_ACCEPT = 1;
- public static final int SC_REQ_ACCEPT_CHARSET = 2;
- public static final int SC_REQ_ACCEPT_ENCODING = 3;
- public static final int SC_REQ_ACCEPT_LANGUAGE = 4;
- public static final int SC_REQ_AUTHORIZATION = 5;
- public static final int SC_REQ_CONNECTION = 6;
- public static final int SC_REQ_CONTENT_TYPE = 7;
- public static final int SC_REQ_CONTENT_LENGTH = 8;
- public static final int SC_REQ_COOKIE = 9;
- public static final int SC_REQ_COOKIE2 = 10;
- public static final int SC_REQ_HOST = 11;
- public static final int SC_REQ_PRAGMA = 12;
- public static final int SC_REQ_REFERER = 13;
- public static final int SC_REQ_USER_AGENT = 14;
- // AJP14 new header
- public static final byte SC_A_SSL_KEY_SIZE = 11; // XXX ???
-
- /**
- * Translates integer codes to request header names
- */
- public static final String []headerTransArray = {
- "accept",
- "accept-charset",
- "accept-encoding",
- "accept-language",
- "authorization",
- "connection",
- "content-type",
- "content-length",
- "cookie",
- "cookie2",
- "host",
- "pragma",
- "referer",
- "user-agent"
- };
- // Ajp13 specific - needs refactoring for the new model
- /**
- * Maximum Total byte size for a AJP packet
- */
- public static final int MAX_PACKET_SIZE=8192;
- /**
- * Size of basic packet header
- */
- public static final int H_SIZE=4;
- /**
- * Maximum size of data that can be sent in one packet
- */
- public static final int MAX_READ_SIZE = MAX_PACKET_SIZE - H_SIZE - 2;
-
-}
+++ /dev/null
-/*
- * 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.jk.common;
-
-import java.util.Set;
-import java.util.Iterator;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.Selector;
-import java.nio.channels.SelectionKey;
-import java.nio.channels.SocketChannel;
-import java.nio.channels.ClosedSelectorException;
-import java.nio.channels.ServerSocketChannel;
-import java.nio.channels.CancelledKeyException;
-import java.nio.channels.ClosedChannelException;
-import java.net.URLEncoder;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.SocketException;
-import java.net.SocketTimeoutException;
-
-import javax.management.ListenerNotFoundException;
-import javax.management.MBeanNotificationInfo;
-import javax.management.Notification;
-import javax.management.NotificationBroadcaster;
-import javax.management.NotificationBroadcasterSupport;
-import javax.management.NotificationFilter;
-import javax.management.NotificationListener;
-import javax.management.ObjectName;
-
-import org.apache.tomcat.util.modeler.Registry;
-import org.apache.jk.core.JkHandler;
-import org.apache.jk.core.Msg;
-import org.apache.jk.core.MsgContext;
-import org.apache.jk.core.JkChannel;
-import org.apache.jk.core.WorkerEnv;
-import org.apache.coyote.Request;
-import org.apache.coyote.RequestGroupInfo;
-import org.apache.coyote.RequestInfo;
-import org.apache.coyote.ActionCode;
-import org.apache.tomcat.util.threads.ThreadPool;
-import org.apache.tomcat.util.threads.ThreadPoolRunnable;
-
-/**
- * Accept ( and send ) TCP messages.
- *
- * @author Costin Manolache
- * @author Bill Barker
- * jmx:mbean name="jk:service=ChannelNioSocket"
- * description="Accept socket connections"
- * jmx:notification name="org.apache.coyote.INVOKE
- * jmx:notification-handler name="org.apache.jk.JK_SEND_PACKET
- * jmx:notification-handler name="org.apache.jk.JK_RECEIVE_PACKET
- * jmx:notification-handler name="org.apache.jk.JK_FLUSH
- *
- * Jk can use multiple protocols/transports.
- * Various container adapters should load this object ( as a bean ),
- * set configurations and use it. Note that the connector will handle
- * all incoming protocols - it's not specific to ajp1x. The protocol
- * is abstracted by MsgContext/Message/Channel.
- *
- * A lot of the 'original' behavior is hardcoded - this uses Ajp13 wire protocol,
- * TCP, Ajp14 API etc.
- * As we add other protocols/transports/APIs this will change, the current goal
- * is to get the same level of functionality as in the original jk connector.
- *
- * XXX Make the 'message type' pluggable
- */
-public class ChannelNioSocket extends JkHandler
- implements NotificationBroadcaster, JkChannel {
- private static org.apache.juli.logging.Log log =
- org.apache.juli.logging.LogFactory.getLog( ChannelNioSocket.class );
-
- private int startPort=8009;
- private int maxPort=8019; // 0 for backward compat.
- private int port=startPort;
- private InetAddress inet;
- private int serverTimeout = 0;
- private boolean tcpNoDelay=true; // nodelay to true by default
- private int linger=100;
- private int socketTimeout = 0;
- private boolean nioIsBroken = false;
- private Selector selector = null;
- private int bufferSize = AjpConstants.MAX_PACKET_SIZE;
- private int packetSize = AjpConstants.MAX_PACKET_SIZE;
-
- private long requestCount=0;
-
- /* Turning this to true will reduce the latency with about 20%.
- But it requires changes in tomcat to make sure client-requested
- flush() is honored ( on my test, I got 367->433 RPS and
- 52->35ms average time with a simple servlet )
- */
-
- ThreadPool tp=ThreadPool.createThreadPool(true);
-
- /* ==================== Tcp socket options ==================== */
-
- /**
- * jmx:managed-constructor description="default constructor"
- */
- public ChannelNioSocket() {
- // This should be integrated with the domain setup
- }
-
- public ThreadPool getThreadPool() {
- return tp;
- }
-
- public long getRequestCount() {
- return requestCount;
- }
-
- /** Set the port for the ajp13 channel.
- * To support seemless load balancing and jni, we treat this
- * as the 'base' port - we'll try up until we find one that is not
- * used. We'll also provide the 'difference' to the main coyote
- * handler - that will be our 'sessionID' and the position in
- * the scoreboard and the suffix for the unix domain socket.
- *
- * jmx:managed-attribute description="Port to listen" access="READ_WRITE"
- */
- public void setPort( int port ) {
- this.startPort=port;
- this.port=port;
- this.maxPort=port+10;
- }
-
- public int getPort() {
- return port;
- }
-
- public void setAddress(InetAddress inet) {
- this.inet=inet;
- }
-
- public void setBufferSize(int bs) {
- if(bs > AjpConstants.MAX_PACKET_SIZE) {
- bufferSize = bs;
- }
- }
-
- public int getBufferSize() {
- return bufferSize;
- }
-
- public void setPacketSize(int ps) {
- if(ps < AjpConstants.MAX_PACKET_SIZE) {
- ps = AjpConstants.MAX_PACKET_SIZE;
- }
- packetSize = ps;
- }
-
- public int getPacketSize() {
- return packetSize;
- }
-
- /**
- * jmx:managed-attribute description="Bind on a specified address" access="READ_WRITE"
- */
- public void setAddress(String inet) {
- try {
- this.inet= InetAddress.getByName( inet );
- } catch( Exception ex ) {
- log.error("Error parsing "+inet,ex);
- }
- }
-
- public String getAddress() {
- if( inet!=null)
- return inet.toString();
- return "/0.0.0.0";
- }
-
- /**
- * Sets the timeout in ms of the server sockets created by this
- * server. This method allows the developer to make servers
- * more or less responsive to having their server sockets
- * shut down.
- *
- * <p>By default this value is 1000ms.
- */
- public void setServerTimeout(int timeout) {
- this.serverTimeout = timeout;
- }
- public int getServerTimeout() {
- return serverTimeout;
- }
-
- public void setTcpNoDelay( boolean b ) {
- tcpNoDelay=b;
- }
-
- public boolean getTcpNoDelay() {
- return tcpNoDelay;
- }
-
- public void setSoLinger( int i ) {
- linger=i;
- }
-
- public int getSoLinger() {
- return linger;
- }
-
- public void setSoTimeout( int i ) {
- socketTimeout=i;
- }
-
- public int getSoTimeout() {
- return socketTimeout;
- }
-
- public void setMaxPort( int i ) {
- maxPort=i;
- }
-
- public int getMaxPort() {
- return maxPort;
- }
-
- /** At startup we'll look for the first free port in the range.
- The difference between this port and the beggining of the range
- is the 'id'.
- This is usefull for lb cases ( less config ).
- */
- public int getInstanceId() {
- return port-startPort;
- }
-
- /** If set to false, the thread pool will be created in
- * non-daemon mode, and will prevent main from exiting
- */
- public void setDaemon( boolean b ) {
- tp.setDaemon( b );
- }
-
- public boolean getDaemon() {
- return tp.getDaemon();
- }
-
-
- public void setMaxThreads( int i ) {
- if( log.isDebugEnabled()) log.debug("Setting maxThreads " + i);
- tp.setMaxThreads(i);
- }
-
- public void setMinSpareThreads( int i ) {
- if( log.isDebugEnabled()) log.debug("Setting minSpareThreads " + i);
- tp.setMinSpareThreads(i);
- }
-
- public void setMaxSpareThreads( int i ) {
- if( log.isDebugEnabled()) log.debug("Setting maxSpareThreads " + i);
- tp.setMaxSpareThreads(i);
- }
-
- public int getMaxThreads() {
- return tp.getMaxThreads();
- }
-
- public int getMinSpareThreads() {
- return tp.getMinSpareThreads();
- }
-
- public int getMaxSpareThreads() {
- return tp.getMaxSpareThreads();
- }
-
- public void setBacklog(int i) {
- }
-
- public void setNioIsBroken(boolean nib) {
- nioIsBroken = nib;
- }
-
- public boolean getNioIsBroken() {
- return nioIsBroken;
- }
-
- /* ==================== ==================== */
- ServerSocket sSocket;
- final int socketNote=1;
- final int isNote=2;
- final int osNote=3;
- final int notifNote=4;
- boolean paused = false;
-
- public void pause() throws Exception {
- synchronized(this) {
- paused = true;
- }
- }
-
- public void resume() {
- synchronized(this) {
- paused = false;
- notify();
- }
- }
-
-
- public void accept( MsgContext ep ) throws IOException {
- if( sSocket==null ) return;
- synchronized(this) {
- while(paused) {
- try{
- wait();
- } catch(InterruptedException ie) {
- //Ignore, since can't happen
- }
- }
- }
- SocketChannel sc=sSocket.getChannel().accept();
- Socket s = sc.socket();
- ep.setNote( socketNote, s );
- if(log.isDebugEnabled() )
- log.debug("Accepted socket " + s +" channel " + sc.isBlocking());
-
- try {
- setSocketOptions(s);
- } catch(SocketException sex) {
- log.debug("Error initializing Socket Options", sex);
- }
-
- requestCount++;
-
- sc.configureBlocking(false);
- InputStream is=new SocketInputStream(sc);
- OutputStream os = new SocketOutputStream(sc);
- ep.setNote( isNote, is );
- ep.setNote( osNote, os );
- ep.setControl( tp );
- }
-
- private void setSocketOptions(Socket s) throws SocketException {
- if( socketTimeout > 0 )
- s.setSoTimeout( socketTimeout );
-
- s.setTcpNoDelay( tcpNoDelay ); // set socket tcpnodelay state
-
- if( linger > 0 )
- s.setSoLinger( true, linger);
- }
-
- public void resetCounters() {
- requestCount=0;
- }
-
- /** Called after you change some fields at runtime using jmx.
- Experimental for now.
- */
- public void reinit() throws IOException {
- destroy();
- init();
- }
-
- /**
- * jmx:managed-operation
- */
- public void init() throws IOException {
- // Find a port.
- if (startPort == 0) {
- port = 0;
- if(log.isInfoEnabled())
- log.info("JK: ajp13 disabling channelNioSocket");
- running = true;
- return;
- }
- if (maxPort < startPort)
- maxPort = startPort;
- ServerSocketChannel ssc = ServerSocketChannel.open();
- ssc.configureBlocking(false);
- for( int i=startPort; i<=maxPort; i++ ) {
- try {
- InetSocketAddress iddr = null;
- if( inet == null ) {
- iddr = new InetSocketAddress( i);
- } else {
- iddr=new InetSocketAddress( inet, i);
- }
- sSocket = ssc.socket();
- sSocket.bind(iddr);
- port=i;
- break;
- } catch( IOException ex ) {
- if(log.isInfoEnabled())
- log.info("Port busy " + i + " " + ex.toString());
- sSocket = null;
- }
- }
-
- if( sSocket==null ) {
- log.error("Can't find free port " + startPort + " " + maxPort );
- return;
- }
- if(log.isInfoEnabled())
- log.info("JK: ajp13 listening on " + getAddress() + ":" + port );
-
- selector = Selector.open();
- ssc.register(selector, SelectionKey.OP_ACCEPT);
- // If this is not the base port and we are the 'main' channleSocket and
- // SHM didn't already set the localId - we'll set the instance id
- if( "channelNioSocket".equals( name ) &&
- port != startPort &&
- (wEnv.getLocalId()==0) ) {
- wEnv.setLocalId( port - startPort );
- }
-
- // XXX Reverse it -> this is a notification generator !!
- if( next==null && wEnv!=null ) {
- if( nextName!=null )
- setNext( wEnv.getHandler( nextName ) );
- if( next==null )
- next=wEnv.getHandler( "dispatch" );
- if( next==null )
- next=wEnv.getHandler( "request" );
- }
- JMXRequestNote =wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "requestNote");
- running = true;
-
- // Run a thread that will accept connections.
- // XXX Try to find a thread first - not sure how...
- if( this.domain != null ) {
- try {
- tpOName=new ObjectName(domain + ":type=ThreadPool,name=" +
- getChannelName());
-
- Registry.getRegistry(null, null)
- .registerComponent(tp, tpOName, null);
-
- rgOName = new ObjectName
- (domain+":type=GlobalRequestProcessor,name=" + getChannelName());
- Registry.getRegistry(null, null)
- .registerComponent(global, rgOName, null);
- } catch (Exception e) {
- log.error("Can't register threadpool" );
- }
- }
-
- tp.start();
- Poller pollAjp = new Poller();
- tp.runIt(pollAjp);
- }
-
- ObjectName tpOName;
- ObjectName rgOName;
- RequestGroupInfo global=new RequestGroupInfo();
- int JMXRequestNote;
-
- public void start() throws IOException{
- if( sSocket==null )
- init();
- resume();
- }
-
- public void stop() throws IOException {
- destroy();
- }
-
- public void registerRequest(Request req, MsgContext ep, int count) {
- if(this.domain != null) {
- try {
- RequestInfo rp=req.getRequestProcessor();
- rp.setGlobalProcessor(global);
- ObjectName roname = new ObjectName
- (getDomain() + ":type=RequestProcessor,worker="+
- getChannelName()+",name=JkRequest" +count);
- ep.setNote(JMXRequestNote, roname);
-
- Registry.getRegistry(null, null).registerComponent( rp, roname, null);
- } catch( Exception ex ) {
- log.warn("Error registering request");
- }
- }
- }
-
- public void open(MsgContext ep) throws IOException {
- }
-
-
- public void close(MsgContext ep) throws IOException {
- Socket s=(Socket)ep.getNote( socketNote );
- SelectionKey key = s.getChannel().keyFor(selector);
- if(key != null) {
- key.cancel();
- }
- s.close();
- }
-
- public void destroy() throws IOException {
- running = false;
- try {
- /* If we disabled the channel return */
- if (port == 0)
- return;
- tp.shutdown();
-
- selector.wakeup().close();
- sSocket.close(); // XXX?
-
- if( tpOName != null ) {
- Registry.getRegistry(null, null).unregisterComponent(tpOName);
- }
- if( rgOName != null ) {
- Registry.getRegistry(null, null).unregisterComponent(rgOName);
- }
- } catch(Exception e) {
- log.info("Error shutting down the channel " + port + " " +
- e.toString());
- if( log.isDebugEnabled() ) log.debug("Trace", e);
- }
- }
-
- public int send( Msg msg, MsgContext ep)
- throws IOException {
- msg.end(); // Write the packet header
- byte buf[]=msg.getBuffer();
- int len=msg.getLen();
-
- if(log.isTraceEnabled() )
- log.trace("send() " + len + " " + buf[4] );
-
- OutputStream os=(OutputStream)ep.getNote( osNote );
- os.write( buf, 0, len );
- return len;
- }
-
- public int flush( Msg msg, MsgContext ep)
- throws IOException {
- OutputStream os=(OutputStream)ep.getNote( osNote );
- os.flush();
- return 0;
- }
-
- public int receive( Msg msg, MsgContext ep )
- throws IOException {
- if (log.isTraceEnabled()) {
- log.trace("receive() ");
- }
-
- byte buf[]=msg.getBuffer();
- int hlen=msg.getHeaderLength();
-
- // XXX If the length in the packet header doesn't agree with the
- // actual number of bytes read, it should probably return an error
- // value. Also, callers of this method never use the length
- // returned -- should probably return true/false instead.
-
- int rd = this.read(ep, buf, 0, hlen );
-
- if(rd < 0) {
- // Most likely normal apache restart.
- // log.warn("Wrong message " + rd );
- return rd;
- }
-
- msg.processHeader();
-
- /* After processing the header we know the body
- length
- */
- int blen=msg.getLen();
-
- // XXX check if enough space - it's assert()-ed !!!
-
- int total_read = 0;
-
- total_read = this.read(ep, buf, hlen, blen);
-
- if ((total_read <= 0) && (blen > 0)) {
- log.warn("can't read body, waited #" + blen);
- return -1;
- }
-
- if (total_read != blen) {
- log.warn( "incomplete read, waited #" + blen +
- " got only " + total_read);
- return -2;
- }
-
- return total_read;
- }
-
- /**
- * Read N bytes from the InputStream, and ensure we got them all
- * Under heavy load we could experience many fragmented packets
- * just read Unix Network Programming to recall that a call to
- * read didn't ensure you got all the data you want
- *
- * from read() Linux manual
- *
- * On success, the number of bytes read is returned (zero indicates end
- * of file),and the file position is advanced by this number.
- * It is not an error if this number is smaller than the number of bytes
- * requested; this may happen for example because fewer bytes
- * are actually available right now (maybe because we were close to
- * end-of-file, or because we are reading from a pipe, or from a
- * terminal), or because read() was interrupted by a signal.
- * On error, -1 is returned, and errno is set appropriately. In this
- * case it is left unspecified whether the file position (if any) changes.
- *
- **/
- public int read( MsgContext ep, byte[] b, int offset, int len)
- throws IOException
- {
- InputStream is=(InputStream)ep.getNote( isNote );
- int pos = 0;
- int got;
-
- while(pos < len) {
- try {
- got = is.read(b, pos + offset, len - pos);
- } catch(ClosedChannelException sex) {
- if(pos > 0) {
- log.info("Error reading data after "+pos+"bytes",sex);
- } else {
- log.debug("Error reading data", sex);
- }
- got = -1;
- }
- if (log.isTraceEnabled()) {
- log.trace("read() " + b + " " + (b==null ? 0: b.length) + " " +
- offset + " " + len + " = " + got );
- }
-
- // connection just closed by remote.
- if (got <= 0) {
- // This happens periodically, as apache restarts
- // periodically.
- // It should be more gracefull ! - another feature for Ajp14
- // log.warn( "server has closed the current connection (-1)" );
- return -3;
- }
-
- pos += got;
- }
- return pos;
- }
-
- protected boolean running=true;
-
- /** Accept incoming connections, dispatch to the thread pool
- */
- void acceptConnections() {
- if( running ) {
- try{
- MsgContext ep=createMsgContext(packetSize);
- ep.setSource(this);
- ep.setWorkerEnv( wEnv );
- this.accept(ep);
-
- if( !running ) return;
-
- // Since this is a long-running connection, we don't care
- // about the small GC
- SocketConnection ajpConn=
- new SocketConnection( ep);
- ajpConn.register(ep);
- }catch(Exception ex) {
- if (running)
- log.warn("Exception executing accept" ,ex);
- }
- }
- }
-
-
- // XXX This should become handleNotification
- public int invoke( Msg msg, MsgContext ep ) throws IOException {
- int type=ep.getType();
-
- switch( type ) {
- case JkHandler.HANDLE_RECEIVE_PACKET:
- if( log.isDebugEnabled()) log.debug("RECEIVE_PACKET ?? ");
- return receive( msg, ep );
- case JkHandler.HANDLE_SEND_PACKET:
- return send( msg, ep );
- case JkHandler.HANDLE_FLUSH:
- return flush( msg, ep );
- }
-
- if( log.isTraceEnabled() )
- log.trace("Call next " + type + " " + next);
-
- // Send notification
- if( nSupport!=null ) {
- Notification notif=(Notification)ep.getNote(notifNote);
- if( notif==null ) {
- notif=new Notification("channelNioSocket.message", ep, requestCount );
- ep.setNote( notifNote, notif);
- }
- nSupport.sendNotification(notif);
- }
-
- if( next != null ) {
- return next.invoke( msg, ep );
- } else {
- log.info("No next ");
- }
-
- return OK;
- }
-
- public boolean isSameAddress(MsgContext ep) {
- Socket s=(Socket)ep.getNote( socketNote );
- return isSameAddress( s.getLocalAddress(), s.getInetAddress());
- }
-
- public String getChannelName() {
- String encodedAddr = "";
- if (inet != null && !"0.0.0.0".equals(inet.getHostAddress())) {
- encodedAddr = getAddress();
- if (encodedAddr.startsWith("/"))
- encodedAddr = encodedAddr.substring(1);
- encodedAddr = URLEncoder.encode(encodedAddr) + "-";
- }
- return ("jk-" + encodedAddr + port);
- }
-
- /**
- * Return <code>true</code> if the specified client and server addresses
- * are the same. This method works around a bug in the IBM 1.1.8 JVM on
- * Linux, where the address bytes are returned reversed in some
- * circumstances.
- *
- * @param server The server's InetAddress
- * @param client The client's InetAddress
- */
- public static boolean isSameAddress(InetAddress server, InetAddress client)
- {
- // Compare the byte array versions of the two addresses
- byte serverAddr[] = server.getAddress();
- byte clientAddr[] = client.getAddress();
- if (serverAddr.length != clientAddr.length)
- return (false);
- boolean match = true;
- for (int i = 0; i < serverAddr.length; i++) {
- if (serverAddr[i] != clientAddr[i]) {
- match = false;
- break;
- }
- }
- if (match)
- return (true);
-
- // Compare the reversed form of the two addresses
- for (int i = 0; i < serverAddr.length; i++) {
- if (serverAddr[i] != clientAddr[(serverAddr.length-1)-i])
- return (false);
- }
- return (true);
- }
-
- public void sendNewMessageNotification(Notification notification) {
- if( nSupport!= null )
- nSupport.sendNotification(notification);
- }
-
- private NotificationBroadcasterSupport nSupport= null;
-
- public void addNotificationListener(NotificationListener listener,
- NotificationFilter filter,
- Object handback)
- throws IllegalArgumentException
- {
- if( nSupport==null ) nSupport=new NotificationBroadcasterSupport();
- nSupport.addNotificationListener(listener, filter, handback);
- }
-
- public void removeNotificationListener(NotificationListener listener)
- throws ListenerNotFoundException
- {
- if( nSupport!=null)
- nSupport.removeNotificationListener(listener);
- }
-
- MBeanNotificationInfo notifInfo[]=new MBeanNotificationInfo[0];
-
- public void setNotificationInfo( MBeanNotificationInfo info[]) {
- this.notifInfo=info;
- }
-
- public MBeanNotificationInfo[] getNotificationInfo() {
- return notifInfo;
- }
-
- protected class SocketConnection implements ThreadPoolRunnable {
- MsgContext ep;
- MsgAjp recv = new MsgAjp(packetSize);
- boolean inProgress = false;
-
- SocketConnection(MsgContext ep) {
- this.ep=ep;
- }
-
- public Object[] getInitData() {
- return null;
- }
-
- public void runIt(Object perTh[]) {
- if(!processConnection(ep)) {
- unregister(ep);
- }
- }
-
- public boolean isRunning() {
- return inProgress;
- }
-
- public void setFinished() {
- inProgress = false;
- }
-
- /** Process a single ajp connection.
- */
- boolean processConnection(MsgContext ep) {
- try {
- InputStream sis = (InputStream)ep.getNote(isNote);
- boolean haveInput = true;
- while(haveInput) {
- if( !running || paused ) {
- return false;
- }
- int status= receive( recv, ep );
- if( status <= 0 ) {
- if( status==-3)
- log.debug( "server has been restarted or reset this connection" );
- else
- log.warn("Closing ajp connection " + status );
- return false;
- }
- ep.setLong( MsgContext.TIMER_RECEIVED, System.currentTimeMillis());
-
- ep.setType( 0 );
- // Will call next
- status= invoke( recv, ep );
- if( status != JkHandler.OK ) {
- log.warn("processCallbacks status " + status );
- ep.action(ActionCode.ACTION_CLOSE, ep.getRequest().getResponse());
- return false;
- }
- synchronized(this) {
- synchronized(sis) {
- haveInput = sis.available() > 0;
- }
- if(!haveInput) {
- setFinished();
- } else {
- if(log.isDebugEnabled())
- log.debug("KeepAlive: "+sis.available());
- }
- }
- }
- } catch( Exception ex ) {
- String msg = ex.getMessage();
- if( msg != null && msg.indexOf( "Connection reset" ) >= 0)
- log.debug( "Server has been restarted or reset this connection");
- else if (msg != null && msg.indexOf( "Read timed out" ) >=0 )
- log.debug( "connection timeout reached");
- else
- log.error( "Error, processing connection", ex);
- return false;
- }
- return true;
- }
-
- synchronized void process(SelectionKey sk) {
- if(!sk.isValid()) {
- SocketInputStream sis = (SocketInputStream)ep.getNote(isNote);
- sis.closeIt();
- return;
- }
- if(sk.isReadable()) {
- SocketInputStream sis = (SocketInputStream)ep.getNote(isNote);
- boolean isok = sis.readAvailable();
- if(!inProgress) {
- if(isok) {
- if(sis.available() > 0 || !nioIsBroken){
- inProgress = true;
- tp.runIt(this);
- }
- } else {
- unregister(ep);
- return;
- }
- }
- }
- if(sk.isWritable()) {
- Object os = ep.getNote(osNote);
- synchronized(os) {
- os.notify();
- }
- }
- }
-
- synchronized void unregister(MsgContext ep) {
- try{
- close(ep);
- } catch(Exception e) {
- log.error("Error closing connection", e);
- }
- try{
- Request req = ep.getRequest();
- if( req != null ) {
- ObjectName roname = (ObjectName)ep.getNote(JMXRequestNote);
- if( roname != null ) {
- Registry.getRegistry(null, null).unregisterComponent(roname);
- }
- req.getRequestProcessor().setGlobalProcessor(null);
- }
- } catch( Exception ee) {
- log.error( "Error, releasing connection",ee);
- }
- }
-
- void register(MsgContext ep) {
- Socket s = (Socket)ep.getNote(socketNote);
- try {
- s.getChannel().register(selector, SelectionKey.OP_READ, this);
- } catch(IOException iex) {
- log.error("Unable to register connection",iex);
- unregister(ep);
- }
- }
-
- }
-
- protected class Poller implements ThreadPoolRunnable {
-
- Poller() {
- }
-
- public Object[] getInitData() {
- return null;
- }
-
- public void runIt(Object perTh[]) {
- while(running) {
- try {
- int ns = selector.select(serverTimeout);
- if(log.isDebugEnabled())
- log.debug("Selecting "+ns+" channels");
- if(ns > 0) {
- Set<SelectionKey> sels = selector.selectedKeys();
- Iterator<SelectionKey> it = sels.iterator();
- while(it.hasNext()) {
- SelectionKey sk = it.next();
- if(sk.isAcceptable()) {
- acceptConnections();
- } else {
- SocketConnection sc = (SocketConnection)sk.attachment();
- sc.process(sk);
- }
- it.remove();
- }
- }
- } catch(ClosedSelectorException cse) {
- log.debug("Selector is closed");
- return;
- } catch(CancelledKeyException cke) {
- log.debug("Key Cancelled", cke);
- } catch(IOException iex) {
- log.warn("IO Error in select",iex);
- } catch(Exception ex) {
- log.warn("Error processing select",ex);
- }
- }
- }
- }
-
- protected class SocketInputStream extends InputStream {
- final int BUFFER_SIZE = 8200;
- private ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER_SIZE);
- private SocketChannel channel;
- private boolean blocking = false;
- private boolean isClosed = false;
- private volatile boolean dataAvailable = false;
-
- SocketInputStream(SocketChannel channel) {
- this.channel = channel;
- buffer.limit(0);
- }
-
- public int available() {
- return buffer.remaining();
- }
-
- public void mark(int readlimit) {
- buffer.mark();
- }
-
- public boolean markSupported() {
- return true;
- }
-
- public void reset() {
- buffer.reset();
- }
-
- public synchronized int read() throws IOException {
- if(!checkAvailable(1)) {
- block(1);
- }
- return buffer.get();
- }
-
- private boolean checkAvailable(int nbyte) throws IOException {
- if(isClosed) {
- throw new ClosedChannelException();
- }
- return buffer.remaining() >= nbyte;
- }
-
- private int fill(int nbyte) throws IOException {
- int rem = nbyte;
- int read = 0;
- boolean eof = false;
- byte [] oldData = null;
- if(buffer.remaining() > 0) {
- // should rarely happen, so short-lived GC shouldn't hurt
- // as much as allocating a long-lived buffer for this
- if(log.isDebugEnabled())
- log.debug("Saving old buffer: "+buffer.remaining());
- oldData = new byte[buffer.remaining()];
- buffer.get(oldData);
- }
- buffer.clear();
- if(oldData != null) {
- buffer.put(oldData);
- }
- while(rem > 0) {
- int count = channel.read(buffer);
- if(count < 0) {
- eof = true;
- break;
- } else if(count == 0) {
- log.debug("Failed to recieve signaled read: ");
- break;
- }
- read += count;
- rem -= count;
- }
- buffer.flip();
- return eof ? -1 : read;
- }
-
- synchronized boolean readAvailable() {
- if(blocking) {
- dataAvailable = true;
- notify();
- } else if(dataAvailable) {
- log.debug("Race Condition");
- } else {
- int nr=0;
-
- try {
- nr = fill(1);
- } catch(ClosedChannelException cce) {
- log.debug("Channel is closed",cce);
- nr = -1;
- } catch(IOException iex) {
- log.warn("Exception processing read",iex);
- nr = -1; // Can't handle this yet
- }
- if(nr < 0) {
- closeIt();
- return false;
- } else if(nr == 0) {
- if(!nioIsBroken) {
- dataAvailable = (buffer.remaining() <= 0);
- }
- }
- }
- return true;
- }
-
- synchronized void closeIt() {
- isClosed = true;
- if(blocking)
- notify();
- }
-
- public int read(byte [] data) throws IOException {
- return read(data, 0, data.length);
- }
-
- public synchronized int read(byte [] data, int offset, int len) throws IOException {
- int olen = len;
- while(!checkAvailable(len)) {
- int avail = buffer.remaining();
- if(avail > 0) {
- buffer.get(data, offset, avail);
- }
- len -= avail;
- offset += avail;
- block(len);
- }
- buffer.get(data, offset, len);
- return olen;
- }
-
- private void block(int len) throws IOException {
- if(len <= 0) {
- return;
- }
- if(!dataAvailable) {
- blocking = true;
- if(log.isDebugEnabled())
- log.debug("Waiting for "+len+" bytes to be available");
- try{
- wait(socketTimeout);
- }catch(InterruptedException iex) {
- log.debug("Interrupted",iex);
- }
- blocking = false;
- }
- if(dataAvailable) {
- dataAvailable = false;
- if(fill(len) < 0) {
- isClosed = true;
- }
- } else if(!isClosed) {
- throw new SocketTimeoutException("Read request timed out");
- }
- }
- }
-
- protected class SocketOutputStream extends OutputStream {
- ByteBuffer buffer = ByteBuffer.allocateDirect(bufferSize);
- SocketChannel channel;
-
- SocketOutputStream(SocketChannel channel) {
- this.channel = channel;
- }
-
- public void write(int b) throws IOException {
- if(!checkAvailable(1)) {
- flush();
- }
- buffer.put((byte)b);
- }
-
- public void write(byte [] data) throws IOException {
- write(data, 0, data.length);
- }
-
- public void write(byte [] data, int offset, int len) throws IOException {
- if(!checkAvailable(len)) {
- flush();
- }
- buffer.put(data, offset, len);
- }
-
- public void flush() throws IOException {
- buffer.flip();
- while(buffer.hasRemaining()) {
- int count = channel.write(buffer);
- if(count == 0) {
- synchronized(this) {
- SelectionKey key = channel.keyFor(selector);
- key.interestOps(SelectionKey.OP_WRITE);
- if(log.isDebugEnabled())
- log.debug("Blocking for channel write: "+buffer.remaining());
- try {
- wait();
- } catch(InterruptedException iex) {
- // ignore, since can't happen
- }
- key.interestOps(SelectionKey.OP_READ);
- }
- }
- }
- buffer.clear();
- }
-
- private boolean checkAvailable(int len) {
- return buffer.remaining() >= len;
- }
- }
-
-}
-
+++ /dev/null
-/*
- * 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.jk.common;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URLEncoder;
-import java.net.InetAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.SocketException;
-
-import javax.management.ListenerNotFoundException;
-import javax.management.MBeanNotificationInfo;
-import javax.management.Notification;
-import javax.management.NotificationBroadcaster;
-import javax.management.NotificationBroadcasterSupport;
-import javax.management.NotificationFilter;
-import javax.management.NotificationListener;
-import javax.management.ObjectName;
-
-import org.apache.jk.core.JkHandler;
-import org.apache.jk.core.Msg;
-import org.apache.jk.core.MsgContext;
-import org.apache.jk.core.JkChannel;
-import org.apache.jk.core.WorkerEnv;
-import org.apache.coyote.Request;
-import org.apache.coyote.RequestGroupInfo;
-import org.apache.coyote.RequestInfo;
-import org.apache.coyote.ActionCode;
-import org.apache.tomcat.util.modeler.Registry;
-import org.apache.tomcat.util.threads.ThreadPool;
-import org.apache.tomcat.util.threads.ThreadPoolRunnable;
-
-/**
- * Accept ( and send ) TCP messages.
- *
- * @author Costin Manolache
- * @author Bill Barker
- * jmx:mbean name="jk:service=ChannelNioSocket"
- * description="Accept socket connections"
- * jmx:notification name="org.apache.coyote.INVOKE
- * jmx:notification-handler name="org.apache.jk.JK_SEND_PACKET
- * jmx:notification-handler name="org.apache.jk.JK_RECEIVE_PACKET
- * jmx:notification-handler name="org.apache.jk.JK_FLUSH
- *
- * Jk can use multiple protocols/transports.
- * Various container adapters should load this object ( as a bean ),
- * set configurations and use it. Note that the connector will handle
- * all incoming protocols - it's not specific to ajp1x. The protocol
- * is abstracted by MsgContext/Message/Channel.
- *
- * A lot of the 'original' behavior is hardcoded - this uses Ajp13 wire protocol,
- * TCP, Ajp14 API etc.
- * As we add other protocols/transports/APIs this will change, the current goal
- * is to get the same level of functionality as in the original jk connector.
- *
- * XXX Make the 'message type' pluggable
- */
-public class ChannelSocket extends JkHandler
- implements NotificationBroadcaster, JkChannel {
- private static org.apache.juli.logging.Log log =
- org.apache.juli.logging.LogFactory.getLog( ChannelSocket.class );
-
- private int startPort=8009;
- private int maxPort=8019; // 0 for backward compat.
- private int port=startPort;
- private InetAddress inet;
- private int serverTimeout;
- private boolean tcpNoDelay=true; // nodelay to true by default
- private int linger=100;
- private int socketTimeout;
- private int bufferSize = -1;
- private int packetSize = AjpConstants.MAX_PACKET_SIZE;
-
- private long requestCount=0;
-
- ThreadPool tp=ThreadPool.createThreadPool(true);
-
- /* ==================== Tcp socket options ==================== */
-
- /**
- * jmx:managed-constructor description="default constructor"
- */
- public ChannelSocket() {
- // This should be integrated with the domain setup
- }
-
- public ThreadPool getThreadPool() {
- return tp;
- }
-
- public long getRequestCount() {
- return requestCount;
- }
-
- /** Set the port for the ajp13 channel.
- * To support seemless load balancing and jni, we treat this
- * as the 'base' port - we'll try up until we find one that is not
- * used. We'll also provide the 'difference' to the main coyote
- * handler - that will be our 'sessionID' and the position in
- * the scoreboard and the suffix for the unix domain socket.
- *
- * jmx:managed-attribute description="Port to listen" access="READ_WRITE"
- */
- public void setPort( int port ) {
- this.startPort=port;
- this.port=port;
- this.maxPort=port+10;
- }
-
- public int getPort() {
- return port;
- }
-
- public void setAddress(InetAddress inet) {
- this.inet=inet;
- }
-
- /**
- * jmx:managed-attribute description="Bind on a specified address" access="READ_WRITE"
- */
- public void setAddress(String inet) {
- try {
- this.inet= InetAddress.getByName( inet );
- } catch( Exception ex ) {
- log.error("Error parsing "+inet,ex);
- }
- }
-
- public String getAddress() {
- if( inet!=null)
- return inet.toString();
- return "/0.0.0.0";
- }
-
- /**
- * Sets the timeout in ms of the server sockets created by this
- * server. This method allows the developer to make servers
- * more or less responsive to having their server sockets
- * shut down.
- *
- * <p>By default this value is 1000ms.
- */
- public void setServerTimeout(int timeout) {
- this.serverTimeout = timeout;
- }
- public int getServerTimeout() {
- return serverTimeout;
- }
-
- public void setTcpNoDelay( boolean b ) {
- tcpNoDelay=b;
- }
-
- public boolean getTcpNoDelay() {
- return tcpNoDelay;
- }
-
- public void setSoLinger( int i ) {
- linger=i;
- }
-
- public int getSoLinger() {
- return linger;
- }
-
- public void setSoTimeout( int i ) {
- socketTimeout=i;
- }
-
- public int getSoTimeout() {
- return socketTimeout;
- }
-
- public void setMaxPort( int i ) {
- maxPort=i;
- }
-
- public int getMaxPort() {
- return maxPort;
- }
-
- public void setBufferSize(int bs) {
- bufferSize = bs;
- }
-
- public int getBufferSize() {
- return bufferSize;
- }
-
- public void setPacketSize(int ps) {
- if(ps < AjpConstants.MAX_PACKET_SIZE) {
- ps = AjpConstants.MAX_PACKET_SIZE;
- }
- packetSize = ps;
- }
-
- public int getPacketSize() {
- return packetSize;
- }
-
- /** At startup we'll look for the first free port in the range.
- The difference between this port and the beggining of the range
- is the 'id'.
- This is usefull for lb cases ( less config ).
- */
- public int getInstanceId() {
- return port-startPort;
- }
-
- /** If set to false, the thread pool will be created in
- * non-daemon mode, and will prevent main from exiting
- */
- public void setDaemon( boolean b ) {
- tp.setDaemon( b );
- }
-
- public boolean getDaemon() {
- return tp.getDaemon();
- }
-
-
- public void setMaxThreads( int i ) {
- if( log.isDebugEnabled()) log.debug("Setting maxThreads " + i);
- tp.setMaxThreads(i);
- }
-
- public void setMinSpareThreads( int i ) {
- if( log.isDebugEnabled()) log.debug("Setting minSpareThreads " + i);
- tp.setMinSpareThreads(i);
- }
-
- public void setMaxSpareThreads( int i ) {
- if( log.isDebugEnabled()) log.debug("Setting maxSpareThreads " + i);
- tp.setMaxSpareThreads(i);
- }
-
- public int getMaxThreads() {
- return tp.getMaxThreads();
- }
-
- public int getMinSpareThreads() {
- return tp.getMinSpareThreads();
- }
-
- public int getMaxSpareThreads() {
- return tp.getMaxSpareThreads();
- }
-
- public void setBacklog(int i) {
- }
-
-
- /* ==================== ==================== */
- ServerSocket sSocket;
- final int socketNote=1;
- final int isNote=2;
- final int osNote=3;
- final int notifNote=4;
- boolean paused = false;
-
- public void pause() throws Exception {
- synchronized(this) {
- paused = true;
- unLockSocket();
- }
- }
-
- public void resume() throws Exception {
- synchronized(this) {
- paused = false;
- notify();
- }
- }
-
-
- public void accept( MsgContext ep ) throws IOException {
- if( sSocket==null ) return;
- synchronized(this) {
- while(paused) {
- try{
- wait();
- } catch(InterruptedException ie) {
- //Ignore, since can't happen
- }
- }
- }
- Socket s=sSocket.accept();
- ep.setNote( socketNote, s );
- if(log.isDebugEnabled() )
- log.debug("Accepted socket " + s );
-
- try {
- setSocketOptions(s);
- } catch(SocketException sex) {
- log.debug("Error initializing Socket Options", sex);
- }
-
- requestCount++;
-
- InputStream is=new BufferedInputStream(s.getInputStream());
- OutputStream os;
- if( bufferSize > 0 )
- os = new BufferedOutputStream( s.getOutputStream(), bufferSize);
- else
- os = s.getOutputStream();
- ep.setNote( isNote, is );
- ep.setNote( osNote, os );
- ep.setControl( tp );
- }
-
- private void setSocketOptions(Socket s) throws SocketException {
- if( socketTimeout > 0 )
- s.setSoTimeout( socketTimeout );
-
- s.setTcpNoDelay( tcpNoDelay ); // set socket tcpnodelay state
-
- if( linger > 0 )
- s.setSoLinger( true, linger);
- }
-
- public void resetCounters() {
- requestCount=0;
- }
-
- /** Called after you change some fields at runtime using jmx.
- Experimental for now.
- */
- public void reinit() throws IOException {
- destroy();
- init();
- }
-
- /**
- * jmx:managed-operation
- */
- public void init() throws IOException {
- // Find a port.
- if (startPort == 0) {
- port = 0;
- if(log.isInfoEnabled())
- log.info("JK: ajp13 disabling channelSocket");
- running = true;
- return;
- }
- if (maxPort < startPort)
- maxPort = startPort;
- for( int i=startPort; i<=maxPort; i++ ) {
- try {
- if( inet == null ) {
- sSocket = new ServerSocket( i, 0 );
- } else {
- sSocket=new ServerSocket( i, 0, inet );
- }
- port=i;
- break;
- } catch( IOException ex ) {
- if(log.isInfoEnabled())
- log.info("Port busy " + i + " " + ex.toString());
- continue;
- }
- }
-
- if( sSocket==null ) {
- log.error("Can't find free port " + startPort + " " + maxPort );
- return;
- }
- if(log.isInfoEnabled())
- log.info("JK: ajp13 listening on " + getAddress() + ":" + port );
-
- // If this is not the base port and we are the 'main' channleSocket and
- // SHM didn't already set the localId - we'll set the instance id
- if( "channelSocket".equals( name ) &&
- port != startPort &&
- (wEnv.getLocalId()==0) ) {
- wEnv.setLocalId( port - startPort );
- }
- if( serverTimeout > 0 )
- sSocket.setSoTimeout( serverTimeout );
-
- // XXX Reverse it -> this is a notification generator !!
- if( next==null && wEnv!=null ) {
- if( nextName!=null )
- setNext( wEnv.getHandler( nextName ) );
- if( next==null )
- next=wEnv.getHandler( "dispatch" );
- if( next==null )
- next=wEnv.getHandler( "request" );
- }
- JMXRequestNote =wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "requestNote");
- running = true;
-
- // Run a thread that will accept connections.
- // XXX Try to find a thread first - not sure how...
- if( this.domain != null ) {
- try {
- tpOName=new ObjectName(domain + ":type=ThreadPool,name=" +
- getChannelName());
-
- Registry.getRegistry(null, null)
- .registerComponent(tp, tpOName, null);
-
- rgOName = new ObjectName
- (domain+":type=GlobalRequestProcessor,name=" + getChannelName());
- Registry.getRegistry(null, null)
- .registerComponent(global, rgOName, null);
- } catch (Exception e) {
- log.error("Can't register threadpool" );
- }
- }
-
- tp.start();
- SocketAcceptor acceptAjp=new SocketAcceptor( this );
- tp.runIt( acceptAjp);
-
- }
-
- ObjectName tpOName;
- ObjectName rgOName;
- RequestGroupInfo global=new RequestGroupInfo();
- int JMXRequestNote;
-
- public void start() throws IOException{
- if( sSocket==null )
- init();
- }
-
- public void stop() throws IOException {
- destroy();
- }
-
- public void registerRequest(Request req, MsgContext ep, int count) {
- if(this.domain != null) {
- try {
- RequestInfo rp=req.getRequestProcessor();
- rp.setGlobalProcessor(global);
- ObjectName roname = new ObjectName
- (getDomain() + ":type=RequestProcessor,worker="+
- getChannelName()+",name=JkRequest" +count);
- ep.setNote(JMXRequestNote, roname);
-
- Registry.getRegistry(null, null).registerComponent( rp, roname, null);
- } catch( Exception ex ) {
- log.warn("Error registering request");
- }
- }
- }
-
- public void open(MsgContext ep) throws IOException {
- }
-
-
- public void close(MsgContext ep) throws IOException {
- Socket s=(Socket)ep.getNote( socketNote );
- s.close();
- }
-
- private void unLockSocket() throws IOException {
- // Need to create a connection to unlock the accept();
- Socket s;
- InetAddress ladr = inet;
-
- if(port == 0)
- return;
- if (ladr == null || "0.0.0.0".equals(ladr.getHostAddress())) {
- ladr = InetAddress.getLocalHost();
- }
- s=new Socket(ladr, port );
- // setting soLinger to a small value will help shutdown the
- // connection quicker
- s.setSoLinger(true, 0);
-
- s.close();
- }
-
- public void destroy() throws IOException {
- running = false;
- try {
- /* If we disabled the channel return */
- if (port == 0)
- return;
- tp.shutdown();
-
- if(!paused) {
- unLockSocket();
- }
-
- sSocket.close(); // XXX?
-
- if( tpOName != null ) {
- Registry.getRegistry(null, null).unregisterComponent(tpOName);
- }
- if( rgOName != null ) {
- Registry.getRegistry(null, null).unregisterComponent(rgOName);
- }
- } catch(Exception e) {
- log.info("Error shutting down the channel " + port + " " +
- e.toString());
- if( log.isDebugEnabled() ) log.debug("Trace", e);
- }
- }
-
- public int send( Msg msg, MsgContext ep)
- throws IOException {
- msg.end(); // Write the packet header
- byte buf[]=msg.getBuffer();
- int len=msg.getLen();
-
- if(log.isTraceEnabled() )
- log.trace("send() " + len + " " + buf[4] );
-
- OutputStream os=(OutputStream)ep.getNote( osNote );
- os.write( buf, 0, len );
- return len;
- }
-
- public int flush( Msg msg, MsgContext ep)
- throws IOException {
- if( bufferSize > 0 ) {
- OutputStream os=(OutputStream)ep.getNote( osNote );
- os.flush();
- }
- return 0;
- }
-
- public int receive( Msg msg, MsgContext ep )
- throws IOException {
- if (log.isDebugEnabled()) {
- log.debug("receive() ");
- }
-
- byte buf[]=msg.getBuffer();
- int hlen=msg.getHeaderLength();
-
- // XXX If the length in the packet header doesn't agree with the
- // actual number of bytes read, it should probably return an error
- // value. Also, callers of this method never use the length
- // returned -- should probably return true/false instead.
-
- int rd = this.read(ep, buf, 0, hlen );
-
- if(rd < 0) {
- // Most likely normal apache restart.
- // log.warn("Wrong message " + rd );
- return rd;
- }
-
- msg.processHeader();
-
- /* After processing the header we know the body
- length
- */
- int blen=msg.getLen();
-
- // XXX check if enough space - it's assert()-ed !!!
-
- int total_read = 0;
-
- total_read = this.read(ep, buf, hlen, blen);
-
- if ((total_read <= 0) && (blen > 0)) {
- log.warn("can't read body, waited #" + blen);
- return -1;
- }
-
- if (total_read != blen) {
- log.warn( "incomplete read, waited #" + blen +
- " got only " + total_read);
- return -2;
- }
-
- return total_read;
- }
-
- /**
- * Read N bytes from the InputStream, and ensure we got them all
- * Under heavy load we could experience many fragmented packets
- * just read Unix Network Programming to recall that a call to
- * read didn't ensure you got all the data you want
- *
- * from read() Linux manual
- *
- * On success, the number of bytes read is returned (zero indicates end
- * of file),and the file position is advanced by this number.
- * It is not an error if this number is smaller than the number of bytes
- * requested; this may happen for example because fewer bytes
- * are actually available right now (maybe because we were close to
- * end-of-file, or because we are reading from a pipe, or from a
- * terminal), or because read() was interrupted by a signal.
- * On error, -1 is returned, and errno is set appropriately. In this
- * case it is left unspecified whether the file position (if any) changes.
- *
- **/
- public int read( MsgContext ep, byte[] b, int offset, int len)
- throws IOException {
- InputStream is=(InputStream)ep.getNote( isNote );
- int pos = 0;
- int got;
-
- while(pos < len) {
- try {
- got = is.read(b, pos + offset, len - pos);
- } catch(SocketException sex) {
- if(pos > 0) {
- log.info("Error reading data after "+pos+"bytes",sex);
- } else {
- log.debug("Error reading data", sex);
- }
- got = -1;
- }
- if (log.isTraceEnabled()) {
- log.trace("read() " + b + " " + (b==null ? 0: b.length) + " " +
- offset + " " + len + " = " + got );
- }
-
- // connection just closed by remote.
- if (got <= 0) {
- // This happens periodically, as apache restarts
- // periodically.
- // It should be more gracefull ! - another feature for Ajp14
- // log.warn( "server has closed the current connection (-1)" );
- return -3;
- }
-
- pos += got;
- }
- return pos;
- }
-
- protected boolean running=true;
-
- /** Accept incoming connections, dispatch to the thread pool
- */
- void acceptConnections() {
- if( log.isDebugEnabled() )
- log.debug("Accepting ajp connections on " + port);
- while( running ) {
- try{
- MsgContext ep=createMsgContext(packetSize);
- ep.setSource(this);
- ep.setWorkerEnv( wEnv );
- this.accept(ep);
-
- if( !running ) break;
-
- // Since this is a long-running connection, we don't care
- // about the small GC
- SocketConnection ajpConn=
- new SocketConnection(this, ep);
- tp.runIt( ajpConn );
- }catch(Exception ex) {
- if (running)
- log.warn("Exception executing accept" ,ex);
- }
- }
- }
-
- /** Process a single ajp connection.
- */
- void processConnection(MsgContext ep) {
- try {
- MsgAjp recv=new MsgAjp(packetSize);
- while( running ) {
- if(paused) { // Drop the connection on pause
- break;
- }
- int status= this.receive( recv, ep );
- if( status <= 0 ) {
- if( status==-3)
- log.debug( "server has been restarted or reset this connection" );
- else
- log.warn("Closing ajp connection " + status );
- break;
- }
- ep.setLong( MsgContext.TIMER_RECEIVED, System.currentTimeMillis());
-
- ep.setType( 0 );
- // Will call next
- status= this.invoke( recv, ep );
- if( status!= JkHandler.OK ) {
- log.warn("processCallbacks status " + status );
- ep.action(ActionCode.ACTION_CLOSE, ep.getRequest().getResponse());
- break;
- }
- }
- } catch( Exception ex ) {
- String msg = ex.getMessage();
- if( msg != null && msg.indexOf( "Connection reset" ) >= 0)
- log.debug( "Server has been restarted or reset this connection");
- else if (msg != null && msg.indexOf( "Read timed out" ) >=0 )
- log.debug( "connection timeout reached");
- else
- log.error( "Error, processing connection", ex);
- } finally {
- /*
- * Whatever happened to this connection (remote closed it, timeout, read error)
- * the socket SHOULD be closed, or we may be in situation where the webserver
- * will continue to think the socket is still open and will forward request
- * to tomcat without receiving ever a reply
- */
- try {
- this.close( ep );
- }
- catch( Exception e) {
- log.error( "Error, closing connection", e);
- }
- try{
- Request req = ep.getRequest();
- if( req != null ) {
- ObjectName roname = (ObjectName)ep.getNote(JMXRequestNote);
- if( roname != null ) {
- Registry.getRegistry(null, null).unregisterComponent(roname);
- }
- req.getRequestProcessor().setGlobalProcessor(null);
- }
- } catch( Exception ee) {
- log.error( "Error, releasing connection",ee);
- }
- }
- }
-
- // XXX This should become handleNotification
- public int invoke( Msg msg, MsgContext ep ) throws IOException {
- int type=ep.getType();
-
- switch( type ) {
- case JkHandler.HANDLE_RECEIVE_PACKET:
- if( log.isDebugEnabled()) log.debug("RECEIVE_PACKET ?? ");
- return receive( msg, ep );
- case JkHandler.HANDLE_SEND_PACKET:
- return send( msg, ep );
- case JkHandler.HANDLE_FLUSH:
- return flush( msg, ep );
- }
-
- if( log.isDebugEnabled() )
- log.debug("Call next " + type + " " + next);
-
- // Send notification
- if( nSupport!=null ) {
- Notification notif=(Notification)ep.getNote(notifNote);
- if( notif==null ) {
- notif=new Notification("channelSocket.message", ep, requestCount );
- ep.setNote( notifNote, notif);
- }
- nSupport.sendNotification(notif);
- }
-
- if( next != null ) {
- return next.invoke( msg, ep );
- } else {
- log.info("No next ");
- }
-
- return OK;
- }
-
- public boolean isSameAddress(MsgContext ep) {
- Socket s=(Socket)ep.getNote( socketNote );
- return isSameAddress( s.getLocalAddress(), s.getInetAddress());
- }
-
- public String getChannelName() {
- String encodedAddr = "";
- if (inet != null && !"0.0.0.0".equals(inet.getHostAddress())) {
- encodedAddr = getAddress();
- if (encodedAddr.startsWith("/"))
- encodedAddr = encodedAddr.substring(1);
- encodedAddr = URLEncoder.encode(encodedAddr) + "-";
- }
- return ("jk-" + encodedAddr + port);
- }
-
- /**
- * Return <code>true</code> if the specified client and server addresses
- * are the same. This method works around a bug in the IBM 1.1.8 JVM on
- * Linux, where the address bytes are returned reversed in some
- * circumstances.
- *
- * @param server The server's InetAddress
- * @param client The client's InetAddress
- */
- public static boolean isSameAddress(InetAddress server, InetAddress client)
- {
- // Compare the byte array versions of the two addresses
- byte serverAddr[] = server.getAddress();
- byte clientAddr[] = client.getAddress();
- if (serverAddr.length != clientAddr.length)
- return (false);
- boolean match = true;
- for (int i = 0; i < serverAddr.length; i++) {
- if (serverAddr[i] != clientAddr[i]) {
- match = false;
- break;
- }
- }
- if (match)
- return (true);
-
- // Compare the reversed form of the two addresses
- for (int i = 0; i < serverAddr.length; i++) {
- if (serverAddr[i] != clientAddr[(serverAddr.length-1)-i])
- return (false);
- }
- return (true);
- }
-
- public void sendNewMessageNotification(Notification notification) {
- if( nSupport!= null )
- nSupport.sendNotification(notification);
- }
-
- private NotificationBroadcasterSupport nSupport= null;
-
- public void addNotificationListener(NotificationListener listener,
- NotificationFilter filter,
- Object handback)
- throws IllegalArgumentException
- {
- if( nSupport==null ) nSupport=new NotificationBroadcasterSupport();
- nSupport.addNotificationListener(listener, filter, handback);
- }
-
- public void removeNotificationListener(NotificationListener listener)
- throws ListenerNotFoundException
- {
- if( nSupport!=null)
- nSupport.removeNotificationListener(listener);
- }
-
- MBeanNotificationInfo notifInfo[]=new MBeanNotificationInfo[0];
-
- public void setNotificationInfo( MBeanNotificationInfo info[]) {
- this.notifInfo=info;
- }
-
- public MBeanNotificationInfo[] getNotificationInfo() {
- return notifInfo;
- }
-
- static class SocketAcceptor implements ThreadPoolRunnable {
- ChannelSocket wajp;
-
- SocketAcceptor(ChannelSocket wajp ) {
- this.wajp=wajp;
- }
-
- public Object[] getInitData() {
- return null;
- }
-
- public void runIt(Object thD[]) {
- wajp.acceptConnections();
- }
- }
-
- static class SocketConnection implements ThreadPoolRunnable {
- ChannelSocket wajp;
- MsgContext ep;
-
- SocketConnection(ChannelSocket wajp, MsgContext ep) {
- this.wajp=wajp;
- this.ep=ep;
- }
-
-
- public Object[] getInitData() {
- return null;
- }
-
- public void runIt(Object perTh[]) {
- wajp.processConnection(ep);
- ep = null;
- }
- }
-
-}
-
+++ /dev/null
-/*
- * 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.jk.common;
-
-import java.io.IOException;
-
-import org.apache.jk.core.JkHandler;
-import org.apache.jk.core.Msg;
-import org.apache.jk.core.MsgContext;
-
-
-
-
-/**
- * Dispatch based on the message type. ( XXX make it more generic,
- * now it's specific to ajp13 ).
- *
- * @author Costin Manolache
- */
-public class HandlerDispatch extends JkHandler
-{
- private static org.apache.juli.logging.Log log=
- org.apache.juli.logging.LogFactory.getLog( HandlerDispatch.class );
-
- public HandlerDispatch()
- {
- }
-
- public void init() {
- }
-
- JkHandler handlers[]=new JkHandler[MAX_HANDLERS];
- String handlerNames[]=new String[MAX_HANDLERS];
-
- static final int MAX_HANDLERS=32;
- static final int RESERVED=16; // reserved names, backward compat
- int currentId=RESERVED;
-
- public int registerMessageType( int id, String name, JkHandler h,
- String sig[] )
- {
- if( log.isDebugEnabled() )
- log.debug( "Register message " + id + " " + h.getName() +
- " " + h.getClass().getName());
- if( id < 0 ) {
- // try to find it by name
- for( int i=0; i< handlerNames.length; i++ ) {
- if( handlerNames[i]==null ) continue;
- if( name.equals( handlerNames[i] ) )
- return i;
- }
- handlers[currentId]=h;
- handlerNames[currentId]=name;
- currentId++;
- return currentId;
- }
- handlers[id]=h;
- handlerNames[currentId]=name;
- return id;
- }
-
-
- // -------------------- Incoming message --------------------
-
- public int invoke(Msg msg, MsgContext ep )
- throws IOException
- {
- int type=msg.peekByte();
- ep.setType( type );
-
- if( type > handlers.length ||
- handlers[type]==null ) {
- if( log.isDebugEnabled() )
- log.debug( "Invalid handler " + type );
- return ERROR;
- }
-
- if( log.isDebugEnabled() )
- log.debug( "Received " + type + " " + handlers[type].getName());
-
- JkHandler handler=handlers[type];
-
- return handler.invoke( msg, ep );
- }
-
- }
+++ /dev/null
-/*
- * 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.jk.common;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.CharConversionException;
-import java.net.InetAddress;
-import java.util.Properties;
-
-import org.apache.coyote.Request;
-import org.apache.coyote.RequestInfo;
-import org.apache.coyote.Response;
-import org.apache.coyote.Constants;
-import org.apache.jk.core.JkHandler;
-import org.apache.jk.core.Msg;
-import org.apache.jk.core.MsgContext;
-import org.apache.jk.core.WorkerEnv;
-import org.apache.jk.core.JkChannel;
-import org.apache.tomcat.util.buf.ByteChunk;
-import org.apache.tomcat.util.buf.CharChunk;
-import org.apache.tomcat.util.buf.HexUtils;
-import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.http.MimeHeaders;
-import org.apache.tomcat.util.net.SSLSupport;
-import org.apache.tomcat.util.threads.ThreadWithAttributes;
-
-/**
- * Handle messages related with basic request information.
- *
- * This object can handle the following incoming messages:
- * - "FORWARD_REQUEST" input message ( sent when a request is passed from the
- * web server )
- * - "RECEIVE_BODY_CHUNK" input ( sent by container to pass more body, in
- * response to GET_BODY_CHUNK )
- *
- * It can handle the following outgoing messages:
- * - SEND_HEADERS. Pass the status code and headers.
- * - SEND_BODY_CHUNK. Send a chunk of body
- * - GET_BODY_CHUNK. Request a chunk of body data
- * - END_RESPONSE. Notify the end of a request processing.
- *
- * @author Henri Gomez [hgomez@apache.org]
- * @author Dan Milstein [danmil@shore.net]
- * @author Keith Wannamaker [Keith@Wannamaker.org]
- * @author Costin Manolache
- */
-public class HandlerRequest extends JkHandler
-{
- private static org.apache.juli.logging.Log log=
- org.apache.juli.logging.LogFactory.getLog( HandlerRequest.class );
-
- /*
- * Note for Host parsing.
- */
- public static final int HOSTBUFFER = 10;
-
- /**
- * Thread lock.
- */
- private static Object lock = new Object();
-
- private HandlerDispatch dispatch;
- private String ajpidDir="conf";
-
-
- public HandlerRequest() {
- }
-
- public void init() {
- dispatch=(HandlerDispatch)wEnv.getHandler( "dispatch" );
- if( dispatch != null ) {
- // register incoming message handlers
- dispatch.registerMessageType( AjpConstants.JK_AJP13_FORWARD_REQUEST,
- "JK_AJP13_FORWARD_REQUEST",
- this, null); // 2
-
- dispatch.registerMessageType( AjpConstants.JK_AJP13_SHUTDOWN,
- "JK_AJP13_SHUTDOWN",
- this, null); // 7
-
- dispatch.registerMessageType( AjpConstants.JK_AJP13_CPING_REQUEST,
- "JK_AJP13_CPING_REQUEST",
- this, null); // 10
- dispatch.registerMessageType( HANDLE_THREAD_END,
- "HANDLE_THREAD_END",
- this, null);
- // register outgoing messages handler
- dispatch.registerMessageType( AjpConstants.JK_AJP13_SEND_BODY_CHUNK, // 3
- "JK_AJP13_SEND_BODY_CHUNK",
- this,null );
- }
-
- tmpBufNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "tmpBuf" );
- secretNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "secret" );
-
- if( next==null )
- next=wEnv.getHandler( "container" );
- if( log.isDebugEnabled() )
- log.debug( "Container handler " + next + " " + next.getName() +
- " " + next.getClass().getName());
-
- // should happen on start()
- generateAjp13Id();
- }
-
- public void setSecret( String s ) {
- requiredSecret=s;
- }
-
- public void setUseSecret( boolean b ) {
- if(b) {
- requiredSecret=Double.toString(Math.random());
- }
- }
-
- public void setDecodedUri( boolean b ) {
- decoded=b;
- }
-
- public boolean isTomcatAuthentication() {
- return tomcatAuthentication;
- }
-
- public void setShutdownEnabled(boolean se) {
- shutdownEnabled = se;
- }
-
- public boolean getShutdownEnabled() {
- return shutdownEnabled;
- }
-
- public void setTomcatAuthentication(boolean newTomcatAuthentication) {
- tomcatAuthentication = newTomcatAuthentication;
- }
-
- public void setAjpidDir( String path ) {
- if( "".equals( path ) ) path=null;
- ajpidDir=path;
- }
-
- /**
- * Set the flag to tell if we JMX register requests.
- */
- public void setRegisterRequests(boolean srr) {
- registerRequests = srr;
- }
-
- /**
- * Get the flag to tell if we JMX register requests.
- */
- public boolean getRegisterRequests() {
- return registerRequests;
- }
-
- /**
- * Set the flag to delay the initial body read
- */
- public void setDelayInitialRead(boolean dir) {
- delayInitialRead = dir;
- }
-
- /**
- * Get the flag to tell if we delay the initial body read
- */
- public boolean getDelayInitialRead() {
- return delayInitialRead;
- }
-
- // -------------------- Ajp13.id --------------------
-
- private void generateAjp13Id() {
- int portInt=8009; // tcpCon.getPort();
- InetAddress address=null; // tcpCon.getAddress();
-
- if( requiredSecret == null || !shutdownEnabled )
- return;
-
- File f1=new File( wEnv.getJkHome() );
- File f2=new File( f1, "conf" );
-
- if( ! f2.exists() ) {
- log.error( "No conf dir for ajp13.id " + f2 );
- return;
- }
-
- File sf=new File( f2, "ajp13.id");
-
- if( log.isDebugEnabled())
- log.debug( "Using stop file: "+sf);
-
- try {
- Properties props=new Properties();
-
- props.put( "port", Integer.toString( portInt ));
- if( address!=null ) {
- props.put( "address", address.getHostAddress() );
- }
- if( requiredSecret !=null ) {
- props.put( "secret", requiredSecret );
- }
-
- FileOutputStream stopF=new FileOutputStream( sf );
- props.store( stopF, "Automatically generated, don't edit" );
- } catch( IOException ex ) {
- if(log.isDebugEnabled())
- log.debug( "Can't create stop file: "+sf,ex );
- }
- }
-
- // -------------------- Incoming message --------------------
- private String requiredSecret=null;
- private int secretNote;
- private int tmpBufNote;
-
- private boolean decoded=true;
- private boolean tomcatAuthentication=true;
- private boolean registerRequests=true;
- private boolean shutdownEnabled=false;
- private boolean delayInitialRead = true;
-
- public int invoke(Msg msg, MsgContext ep )
- throws IOException {
- int type=msg.getByte();
- ThreadWithAttributes twa = null;
- if (Thread.currentThread() instanceof ThreadWithAttributes) {
- twa = (ThreadWithAttributes) Thread.currentThread();
- }
- Object control=ep.getControl();
- MessageBytes tmpMB=(MessageBytes)ep.getNote( tmpBufNote );
- if( tmpMB==null ) {
- tmpMB= MessageBytes.newInstance();
- ep.setNote( tmpBufNote, tmpMB);
- }
-
- if( log.isDebugEnabled() )
- log.debug( "Handling " + type );
-
- switch( type ) {
- case AjpConstants.JK_AJP13_FORWARD_REQUEST:
- try {
- if (twa != null) {
- twa.setCurrentStage(control, "JkDecode");
- }
- decodeRequest( msg, ep, tmpMB );
- if (twa != null) {
- twa.setCurrentStage(control, "JkService");
- twa.setParam(control, ep.getRequest().unparsedURI());
- }
- } catch( Exception ex ) {
- /* If we are here it is because we have a bad header or something like that */
- log.error( "Error decoding request ", ex );
- msg.dump( "Incomming message");
- Response res=ep.getRequest().getResponse();
- if ( res==null ) {
- res=new Response();
- ep.getRequest().setResponse(res);
- }
- res.setMessage("Bad Request");
- res.setStatus(400);
- return ERROR;
- }
-
- if( requiredSecret != null ) {
- String epSecret=(String)ep.getNote( secretNote );
- if( epSecret==null || ! requiredSecret.equals( epSecret ) )
- return ERROR;
- }
- /* XXX it should be computed from request, by workerEnv */
- if(log.isDebugEnabled() )
- log.debug("Calling next " + next.getName() + " " +
- next.getClass().getName());
-
- int err= next.invoke( msg, ep );
- if (twa != null) {
- twa.setCurrentStage(control, "JkDone");
- }
-
- if( log.isDebugEnabled() )
- log.debug( "Invoke returned " + err );
- return err;
- case AjpConstants.JK_AJP13_SHUTDOWN:
- String epSecret=null;
- if( msg.getLen() > 3 ) {
- // we have a secret
- msg.getBytes( tmpMB );
- epSecret=tmpMB.toString();
- }
-
- if( requiredSecret != null &&
- requiredSecret.equals( epSecret ) ) {
- if( log.isDebugEnabled() )
- log.debug("Received wrong secret, no shutdown ");
- return ERROR;
- }
-
- // XXX add isSameAddress check
- JkChannel ch=ep.getSource();
- if( !ch.isSameAddress(ep) ) {
- log.error("Shutdown request not from 'same address' ");
- return ERROR;
- }
-
- if( !shutdownEnabled ) {
- log.warn("Ignoring shutdown request: shutdown not enabled");
- return ERROR;
- }
- // forward to the default handler - it'll do the shutdown
- checkRequest(ep);
- next.invoke( msg, ep );
-
- if(log.isInfoEnabled())
- log.info("Exiting");
- System.exit(0);
-
- return OK;
-
- // We got a PING REQUEST, quickly respond with a PONG
- case AjpConstants.JK_AJP13_CPING_REQUEST:
- msg.reset();
- msg.appendByte(AjpConstants.JK_AJP13_CPONG_REPLY);
- ep.getSource().send( msg, ep );
- ep.getSource().flush( msg, ep ); // Server needs to get it
- return OK;
-
- case HANDLE_THREAD_END:
- return OK;
-
- default:
- if(log.isInfoEnabled())
- log.info("Unknown message " + type);
- }
-
- return OK;
- }
-
- static int count = 0;
-
- private Request checkRequest(MsgContext ep) {
- Request req=ep.getRequest();
- if( req==null ) {
- req=new Request();
- Response res=new Response();
- req.setResponse(res);
- ep.setRequest( req );
- if( registerRequests ) {
- synchronized(lock) {
- ep.getSource().registerRequest(req, ep, count++);
- }
- }
- }
- return req;
- }
-
- private int decodeRequest( Msg msg, MsgContext ep, MessageBytes tmpMB )
- throws IOException {
- // FORWARD_REQUEST handler
- Request req = checkRequest(ep);
-
- RequestInfo rp = req.getRequestProcessor();
- rp.setStage(Constants.STAGE_PARSE);
- MessageBytes tmpMB2 = (MessageBytes)req.getNote(WorkerEnv.SSL_CERT_NOTE);
- if(tmpMB2 != null) {
- tmpMB2.recycle();
- }
- req.setStartTime(System.currentTimeMillis());
-
- // Translate the HTTP method code to a String.
- byte methodCode = msg.getByte();
- if (methodCode != AjpConstants.SC_M_JK_STORED) {
- String mName=AjpConstants.methodTransArray[methodCode - 1];
- req.method().setString(mName);
- }
-
- msg.getBytes(req.protocol());
- msg.getBytes(req.requestURI());
-
- msg.getBytes(req.remoteAddr());
- msg.getBytes(req.remoteHost());
- msg.getBytes(req.localName());
- req.setLocalPort(msg.getInt());
-
- boolean isSSL = msg.getByte() != 0;
- if( isSSL ) {
- // XXX req.setSecure( true );
- req.scheme().setString("https");
- }
-
- decodeHeaders( ep, msg, req, tmpMB );
-
- decodeAttributes( ep, msg, req, tmpMB );
-
- rp.setStage(Constants.STAGE_PREPARE);
- MessageBytes valueMB = req.getMimeHeaders().getValue("host");
- parseHost(valueMB, req);
- // set cookies on request now that we have all headers
- req.getCookies().setHeaders(req.getMimeHeaders());
-
- // Check to see if there should be a body packet coming along
- // immediately after
- long cl=req.getContentLengthLong();
- if(cl > 0) {
- JkInputStream jkIS = ep.getInputStream();
- jkIS.setIsReadRequired(true);
- if(!delayInitialRead) {
- jkIS.receive();
- }
- }
-
- if (log.isTraceEnabled()) {
- log.trace(req.toString());
- }
-
- return OK;
- }
-
- private int decodeAttributes( MsgContext ep, Msg msg, Request req,
- MessageBytes tmpMB) {
- boolean moreAttr=true;
-
- while( moreAttr ) {
- byte attributeCode=msg.getByte();
- if( attributeCode == AjpConstants.SC_A_ARE_DONE )
- return 200;
-
- /* Special case ( XXX in future API make it separate type !)
- */
- if( attributeCode == AjpConstants.SC_A_SSL_KEY_SIZE ) {
- // Bug 1326: it's an Integer.
- req.setAttribute(SSLSupport.KEY_SIZE_KEY,
- new Integer( msg.getInt()));
- //Integer.toString(msg.getInt()));
- }
-
- if( attributeCode == AjpConstants.SC_A_REQ_ATTRIBUTE ) {
- // 2 strings ???...
- msg.getBytes( tmpMB );
- String n=tmpMB.toString();
- msg.getBytes( tmpMB );
- String v=tmpMB.toString();
- /*
- * AJP13 misses to forward the remotePort.
- * Allow the AJP connector to add this info via
- * a private request attribute.
- * We will accept the forwarded data as the remote port,
- * and remove it from the public list of request attributes.
- */
- if(n.equals(AjpConstants.SC_A_REQ_REMOTE_PORT)) {
- try {
- req.setRemotePort(Integer.parseInt(v));
- } catch (NumberFormatException nfe) {
- }
- } else {
- req.setAttribute(n, v );
- if(log.isTraceEnabled())
- log.trace("jk Attribute set " + n + "=" + v);
- }
- }
-
-
- // 1 string attributes
- switch(attributeCode) {
- case AjpConstants.SC_A_CONTEXT :
- msg.getBytes( tmpMB );
- // nothing
- break;
-
- case AjpConstants.SC_A_SERVLET_PATH :
- msg.getBytes( tmpMB );
- // nothing
- break;
-
- case AjpConstants.SC_A_REMOTE_USER :
- if( tomcatAuthentication ) {
- // ignore server
- msg.getBytes( tmpMB );
- } else {
- msg.getBytes(req.getRemoteUser());
- }
- break;
-
- case AjpConstants.SC_A_AUTH_TYPE :
- if( tomcatAuthentication ) {
- // ignore server
- msg.getBytes( tmpMB );
- } else {
- msg.getBytes(req.getAuthType());
- }
- break;
-
- case AjpConstants.SC_A_QUERY_STRING :
- msg.getBytes(req.queryString());
- break;
-
- case AjpConstants.SC_A_JVM_ROUTE :
- msg.getBytes(req.instanceId());
- break;
-
- case AjpConstants.SC_A_SSL_CERT :
- req.scheme().setString( "https" );
- // Transform the string into certificate.
- MessageBytes tmpMB2 = (MessageBytes)req.getNote(WorkerEnv.SSL_CERT_NOTE);
- if(tmpMB2 == null) {
- tmpMB2 = MessageBytes.newInstance();
- req.setNote(WorkerEnv.SSL_CERT_NOTE, tmpMB2);
- }
- // SSL certificate extraction is costy, moved to JkCoyoteHandler
- msg.getBytes(tmpMB2);
- break;
-
- case AjpConstants.SC_A_SSL_CIPHER :
- req.scheme().setString( "https" );
- msg.getBytes(tmpMB);
- req.setAttribute(SSLSupport.CIPHER_SUITE_KEY,
- tmpMB.toString());
- break;
-
- case AjpConstants.SC_A_SSL_SESSION :
- req.scheme().setString( "https" );
- msg.getBytes(tmpMB);
- req.setAttribute(SSLSupport.SESSION_ID_KEY,
- tmpMB.toString());
- break;
-
- case AjpConstants.SC_A_SECRET :
- msg.getBytes(tmpMB);
- String secret=tmpMB.toString();
- if(log.isTraceEnabled())
- log.trace("Secret: " + secret );
- // endpoint note
- ep.setNote( secretNote, secret );
- break;
-
- case AjpConstants.SC_A_STORED_METHOD:
- msg.getBytes(req.method());
- break;
-
- default:
- break; // ignore, we don't know about it - backward compat
- }
- }
- return 200;
- }
-
- private void decodeHeaders( MsgContext ep, Msg msg, Request req,
- MessageBytes tmpMB ) {
- // Decode headers
- MimeHeaders headers = req.getMimeHeaders();
-
- int hCount = msg.getInt();
- for(int i = 0 ; i < hCount ; i++) {
- String hName = null;
-
- // Header names are encoded as either an integer code starting
- // with 0xA0, or as a normal string (in which case the first
- // two bytes are the length).
- int isc = msg.peekInt();
- int hId = isc & 0xFF;
-
- MessageBytes vMB=null;
- isc &= 0xFF00;
- if(0xA000 == isc) {
- msg.getInt(); // To advance the read position
- hName = AjpConstants.headerTransArray[hId - 1];
- vMB=headers.addValue( hName );
- } else {
- // reset hId -- if the header currently being read
- // happens to be 7 or 8 bytes long, the code below
- // will think it's the content-type header or the
- // content-length header - SC_REQ_CONTENT_TYPE=7,
- // SC_REQ_CONTENT_LENGTH=8 - leading to unexpected
- // behaviour. see bug 5861 for more information.
- hId = -1;
- msg.getBytes( tmpMB );
- ByteChunk bc=tmpMB.getByteChunk();
- vMB=headers.addValue( bc.getBuffer(),
- bc.getStart(), bc.getLength() );
- }
-
- msg.getBytes(vMB);
-
- if (hId == AjpConstants.SC_REQ_CONTENT_LENGTH ||
- (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) {
- // just read the content-length header, so set it
- long cl = vMB.getLong();
- if(cl < Integer.MAX_VALUE)
- req.setContentLength( (int)cl );
- } else if (hId == AjpConstants.SC_REQ_CONTENT_TYPE ||
- (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) {
- // just read the content-type header, so set it
- ByteChunk bchunk = vMB.getByteChunk();
- req.contentType().setBytes(bchunk.getBytes(),
- bchunk.getOffset(),
- bchunk.getLength());
- }
- }
- }
-
- /**
- * Parse host.
- */
- private void parseHost(MessageBytes valueMB, Request request)
- throws IOException {
-
- if (valueMB == null || valueMB.isNull()) {
- // HTTP/1.0
- // Default is what the socket tells us. Overriden if a host is
- // found/parsed
- request.setServerPort(request.getLocalPort());
- request.serverName().duplicate(request.localName());
- return;
- }
-
- ByteChunk valueBC = valueMB.getByteChunk();
- byte[] valueB = valueBC.getBytes();
- int valueL = valueBC.getLength();
- int valueS = valueBC.getStart();
- int colonPos = -1;
- CharChunk hostNameC = (CharChunk)request.getNote(HOSTBUFFER);
- if(hostNameC == null) {
- hostNameC = new CharChunk(valueL);
- request.setNote(HOSTBUFFER, hostNameC);
- }
- hostNameC.recycle();
-
- boolean ipv6 = (valueB[valueS] == '[');
- boolean bracketClosed = false;
- for (int i = 0; i < valueL; i++) {
- char b = (char) valueB[i + valueS];
- hostNameC.append(b);
- if (b == ']') {
- bracketClosed = true;
- } else if (b == ':') {
- if (!ipv6 || bracketClosed) {
- colonPos = i;
- break;
- }
- }
- }
-
- if (colonPos < 0) {
- if (request.scheme().equalsIgnoreCase("https")) {
- // 80 - Default HTTTP port
- request.setServerPort(443);
- } else {
- // 443 - Default HTTPS port
- request.setServerPort(80);
- }
- request.serverName().setChars(hostNameC.getChars(),
- hostNameC.getStart(),
- hostNameC.getLength());
- } else {
-
- request.serverName().setChars(hostNameC.getChars(),
- hostNameC.getStart(), colonPos);
-
- int port = 0;
- int mult = 1;
- for (int i = valueL - 1; i > colonPos; i--) {
- int charValue = HexUtils.DEC[valueB[i + valueS]];
- if (charValue == -1) {
- // Invalid character
- throw new CharConversionException("Invalid char in port: " + valueB[i + valueS]);
- }
- port = port + (charValue * mult);
- mult = 10 * mult;
- }
- request.setServerPort(port);
-
- }
-
- }
-
-}
+++ /dev/null
-/*
- * 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.jk.common;
-
-import java.io.IOException;
-
-import org.apache.coyote.OutputBuffer;
-import org.apache.coyote.InputBuffer;
-import org.apache.coyote.Request;
-import org.apache.coyote.Response;
-
-import org.apache.jk.core.Msg;
-import org.apache.jk.core.MsgContext;
-
-import org.apache.tomcat.util.buf.ByteChunk;
-import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.buf.C2BConverter;
-import org.apache.tomcat.util.http.HttpMessages;
-import org.apache.tomcat.util.http.MimeHeaders;
-
-/** Generic input stream impl on top of ajp
- */
-public class JkInputStream implements InputBuffer, OutputBuffer {
- private static org.apache.juli.logging.Log log=
- org.apache.juli.logging.LogFactory.getLog( JkInputStream.class );
-
- private Msg bodyMsg;
- private Msg outputMsg;
- private MsgContext mc;
-
-
- // Holds incoming chunks of request body data
- private MessageBytes bodyBuff = MessageBytes.newInstance();
- private MessageBytes tempMB = MessageBytes.newInstance();
- private boolean end_of_stream=false;
- private boolean isEmpty = true;
- private boolean isFirst = true;
- private boolean isReplay = false;
- private boolean isReadRequired = false;
- private int packetSize = AjpConstants.MAX_PACKET_SIZE;
-
- static {
- // Make certain HttpMessages is loaded for SecurityManager
- try {
- Class.forName("org.apache.tomcat.util.http.HttpMessages");
- } catch(Exception ex) {
- // ignore
- }
- }
-
- public JkInputStream(MsgContext context, int bsize) {
- mc = context;
- // Never use less than the default maximum packet size.
- if (bsize < AjpConstants.MAX_PACKET_SIZE)
- this.packetSize = AjpConstants.MAX_PACKET_SIZE;
- else
- this.packetSize = bsize;
- bodyMsg = new MsgAjp(this.packetSize);
- outputMsg = new MsgAjp(this.packetSize);
- }
- /**
- * @deprecated
- */
- public JkInputStream(MsgContext context) {
- this(context, AjpConstants.MAX_PACKET_SIZE);
- }
-
- // -------------------- Jk specific methods --------------------
-
-
- /**
- * Set the flag saying that the server is sending a body
- */
- public void setIsReadRequired(boolean irr) {
- isReadRequired = irr;
- }
-
- /**
- * Return the flag saying that the server is sending a body
- */
- public boolean isReadRequired() {
- return isReadRequired;
- }
-
-
- /** Must be called before or after each request
- */
- public void recycle() {
- if(isReadRequired && isFirst) {
- // The Servlet never read the request body, so we need to junk it
- try {
- receive();
- } catch(IOException iex) {
- log.debug("Error consuming request body",iex);
- }
- }
-
- end_of_stream = false;
- isEmpty = true;
- isFirst = true;
- isReplay = false;
- isReadRequired = false;
- bodyBuff.recycle();
- tempMB.recycle();
- }
-
-
- public void endMessage() throws IOException {
- outputMsg.reset();
- outputMsg.appendByte(AjpConstants.JK_AJP13_END_RESPONSE);
- outputMsg.appendByte(1);
- mc.getSource().send(outputMsg, mc);
- mc.getSource().flush(outputMsg, mc);
- }
-
-
- // -------------------- OutputBuffer implementation --------------------
-
-
- public int doWrite(ByteChunk chunk, Response res)
- throws IOException {
- if (!res.isCommitted()) {
- // Send the connector a request for commit. The connector should
- // then validate the headers, send them (using sendHeader) and
- // set the filters accordingly.
- res.sendHeaders();
- }
-
- int len=chunk.getLength();
- byte buf[]=outputMsg.getBuffer();
- // 4 - hardcoded, byte[] marshalling overhead
- int chunkSize=buf.length - outputMsg.getHeaderLength() - 4;
- int off=0;
- while( len > 0 ) {
- int thisTime=len;
- if( thisTime > chunkSize ) {
- thisTime=chunkSize;
- }
- len-=thisTime;
-
- outputMsg.reset();
- outputMsg.appendByte( AjpConstants.JK_AJP13_SEND_BODY_CHUNK);
- if( log.isTraceEnabled() )
- log.trace("doWrite " + off + " " + thisTime + " " + len );
- outputMsg.appendBytes( chunk.getBytes(), chunk.getOffset() + off, thisTime );
- off+=thisTime;
- mc.getSource().send( outputMsg, mc );
- }
- return 0;
- }
-
- public int doRead(ByteChunk responseChunk, Request req)
- throws IOException {
-
- if( log.isDebugEnabled())
- log.debug( "doRead " + end_of_stream+
- " " + responseChunk.getOffset()+ " " + responseChunk.getLength());
- if( end_of_stream ) {
- return -1;
- }
-
- if( isFirst && isReadRequired ) {
- // Handle special first-body-chunk, but only if httpd expects it.
- if( !receive() ) {
- return 0;
- }
- } else if(isEmpty) {
- if ( !refillReadBuffer() ){
- return -1;
- }
- }
- ByteChunk bc = bodyBuff.getByteChunk();
- responseChunk.setBytes( bc.getBuffer(), bc.getStart(), bc.getLength() );
- isEmpty = true;
- return responseChunk.getLength();
- }
-
- /** Receive a chunk of data. Called to implement the
- * 'special' packet in ajp13 and to receive the data
- * after we send a GET_BODY packet
- */
- public boolean receive() throws IOException {
- isFirst = false;
- bodyMsg.reset();
- int err = mc.getSource().receive(bodyMsg, mc);
- if( log.isDebugEnabled() )
- log.info( "Receiving: getting request body chunk " + err + " " + bodyMsg.getLen() );
-
- if(err < 0) {
- throw new IOException();
- }
-
- // No data received.
- if( bodyMsg.getLen() == 0 ) { // just the header
- // Don't mark 'end of stream' for the first chunk.
- // end_of_stream = true;
- return false;
- }
- int blen = bodyMsg.peekInt();
-
- if( blen == 0 ) {
- return false;
- }
-
- if( log.isTraceEnabled() ) {
- bodyMsg.dump("Body buffer");
- }
-
- bodyMsg.getBytes(bodyBuff);
- if( log.isTraceEnabled() )
- log.trace( "Data:\n" + bodyBuff);
- isEmpty = false;
- return true;
- }
-
- /**
- * Get more request body data from the web server and store it in the
- * internal buffer.
- *
- * @return true if there is more data, false if not.
- */
- private boolean refillReadBuffer() throws IOException
- {
- // If the server returns an empty packet, assume that that end of
- // the stream has been reached (yuck -- fix protocol??).
- if(isReplay) {
- end_of_stream = true; // we've read everything there is
- }
- if (end_of_stream) {
- if( log.isDebugEnabled() )
- log.debug("refillReadBuffer: end of stream " );
- return false;
- }
-
- // Why not use outBuf??
- bodyMsg.reset();
- bodyMsg.appendByte(AjpConstants.JK_AJP13_GET_BODY_CHUNK);
- // Adjust allowed size if packetSize != default (AjpConstants.MAX_PACKET_SIZE)
- bodyMsg.appendInt(AjpConstants.MAX_READ_SIZE + packetSize - AjpConstants.MAX_PACKET_SIZE);
-
- if( log.isDebugEnabled() )
- log.debug("refillReadBuffer " + Thread.currentThread());
-
- mc.getSource().send(bodyMsg, mc);
- mc.getSource().flush(bodyMsg, mc); // Server needs to get it
-
- // In JNI mode, response will be in bodyMsg. In TCP mode, response need to be
- // read
-
- boolean moreData=receive();
- if( !moreData ) {
- end_of_stream=true;
- }
- return moreData;
- }
-
- public void appendHead(Response res) throws IOException {
- if( log.isDebugEnabled() )
- log.debug("COMMIT sending headers " + res + " " + res.getMimeHeaders() );
-
- C2BConverter c2b=mc.getConverter();
-
- outputMsg.reset();
- outputMsg.appendByte(AjpConstants.JK_AJP13_SEND_HEADERS);
- outputMsg.appendInt( res.getStatus() );
-
- String message = null;
- if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER) {
- message = res.getMessage();
- }
- if( message==null ){
- message= HttpMessages.getMessage(res.getStatus());
- } else {
- message = message.replace('\n', ' ').replace('\r', ' ');
- }
- if (message == null) {
- // mod_jk + httpd 2.x fails with a null status message - bug 45026
- message = Integer.toString(res.getStatus());
- }
- tempMB.setString( message );
- c2b.convert( tempMB );
- outputMsg.appendBytes(tempMB);
-
- // XXX add headers
-
- MimeHeaders headers=res.getMimeHeaders();
- String contentType = res.getContentType();
- if( contentType != null ) {
- headers.setValue("Content-Type").setString(contentType);
- }
- String contentLanguage = res.getContentLanguage();
- if( contentLanguage != null ) {
- headers.setValue("Content-Language").setString(contentLanguage);
- }
- long contentLength = res.getContentLengthLong();
- if( contentLength >= 0 ) {
- headers.setValue("Content-Length").setLong(contentLength);
- }
- int numHeaders = headers.size();
- outputMsg.appendInt(numHeaders);
- for( int i=0; i<numHeaders; i++ ) {
- MessageBytes hN=headers.getName(i);
- // no header to sc conversion - there's little benefit
- // on this direction
- c2b.convert ( hN );
- outputMsg.appendBytes( hN );
-
- MessageBytes hV=headers.getValue(i);
- c2b.convert( hV );
- outputMsg.appendBytes( hV );
- }
- mc.getSource().send( outputMsg, mc );
- }
-
- /**
- * Set the replay buffer for Form auth
- */
- public void setReplay(ByteChunk replay) {
- isFirst = false;
- isEmpty = false;
- isReplay = true;
- bodyBuff.setBytes(replay.getBytes(), replay.getStart(), replay.getLength());
- }
-
-
-}
+++ /dev/null
-/*
- * 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.jk.common;
-
-
-import org.apache.jk.core.JkHandler;
-
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-import javax.management.Attribute;
-import javax.management.MBeanServerFactory;
-import java.io.IOException;
-
-/**
- * Load the HTTP or RMI adapters for MX4J and JMXRI.
- *
- * Add "mx.enabled=true" in jk2.properties to enable it.
- * You could also select http and/or jrmp protocol,
- * with mx.httpPort, mx.httpHost, mxjrmpPort and mx.jrmpPort.
- * <p />
- * If you run into an error message like
- * "SystemId Unknown; Line #12; Column #81; Cannot add attribute name after
- * child nodes or before an element is produced. Attribute will be ignored."
- * after setting mx.enabled to true, you probably need a newer version
- * of Xalan. See the RELEASE-NOTES document section on XML Parsers for
- * more information.
- *
- */
-public class JkMX extends JkHandler
-{
- MBeanServer mserver;
- private boolean enabled=false;
- private boolean log4jEnabled=true;
- private int httpport=-1;
- private String httphost="localhost";
- private String authmode="none";
- private String authuser=null;
- private String authpassword=null;
- private int jrmpport=-1;
- private String jrmphost="localhost";
- private boolean useXSLTProcessor = true;
-
- public JkMX() {
- }
-
- /* -------------------- Public methods -------------------- */
-
- /** Enable the MX4J adapters (new way)
- */
- public void setEnabled(boolean b) {
- enabled=b;
- }
-
- public boolean getEnabled() {
- return enabled;
- }
-
- /** Enable the Log4j MBean)
- */
- public void setLog4jEnabled(boolean b) {
- log4jEnabled=b;
- }
-
- public boolean getLog4jEnabled() {
- return log4jEnabled;
- }
-
- /** Enable the MX4J adapters (old way, compatible)
- */
- public void setPort(int i) {
- enabled=(i != -1);
- }
-
- public int getPort() {
- return ((httpport != -1) ? httpport : jrmpport);
- }
-
- /** Enable the MX4J HTTP internal adapter
- */
- public void setHttpPort( int i ) {
- httpport=i;
- }
-
- public int getHttpPort() {
- return httpport;
- }
-
- public void setHttpHost(String host ) {
- this.httphost=host;
- }
-
- public String getHttpHost() {
- return httphost;
- }
-
- public void setAuthMode(String mode) {
- authmode=mode;
- }
-
- public String getAuthMode() {
- return authmode;
- }
-
- public void setAuthUser(String user) {
- authuser=user;
- }
-
- public String getAuthUser() {
- return authuser;
- }
-
- public void setAuthPassword(String password) {
- authpassword=password;
- }
-
- public String getAuthPassword() {
- return authpassword;
- }
-
- /** Enable the MX4J JRMP internal adapter
- */
- public void setJrmpPort( int i ) {
- jrmpport=i;
- }
-
- public int getJrmpPort() {
- return jrmpport;
- }
-
- public void setJrmpHost(String host ) {
- this.jrmphost=host;
- }
-
- public String getJrmpHost() {
- return jrmphost;
- }
-
- public boolean getUseXSLTProcessor() {
- return useXSLTProcessor;
- }
-
- public void setUseXSLTProcessor(boolean uxsltp) {
- useXSLTProcessor = uxsltp;
- }
-
- /* ==================== Start/stop ==================== */
- ObjectName httpServerName=null;
- ObjectName jrmpServerName=null;
-
- /** Initialize the worker. After this call the worker will be
- * ready to accept new requests.
- */
- public void loadAdapter() throws IOException {
- boolean httpAdapterLoaded = false;
- boolean jrmpAdapterLoaded = false;
-
- if ((httpport != -1) && classExists("mx4j.adaptor.http.HttpAdaptor")) {
- try {
- httpServerName = registerObject("mx4j.adaptor.http.HttpAdaptor",
- "Http:name=HttpAdaptor");
-
-
- if( httphost!=null )
- mserver.setAttribute(httpServerName, new Attribute("Host", httphost));
- mserver.setAttribute(httpServerName, new Attribute("Port", new Integer(httpport)));
-
- if( "none".equals(authmode) || "basic".equals(authmode) || "digest".equals(authmode) )
- mserver.setAttribute(httpServerName, new Attribute("AuthenticationMethod", authmode));
-
- if( authuser!=null && authpassword!=null )
- mserver.invoke(httpServerName, "addAuthorization",
- new Object[] {
- authuser,
- authpassword},
- new String[] { "java.lang.String", "java.lang.String" });
-
- if(useXSLTProcessor) {
- ObjectName processorName = registerObject("mx4j.adaptor.http.XSLTProcessor",
- "Http:name=XSLTProcessor");
- mserver.setAttribute(httpServerName, new Attribute("ProcessorName", processorName));
- }
-
- // starts the server
- mserver.invoke(httpServerName, "start", null, null);
-
- log.info( "Started MX4J console on host " + httphost + " at port " + httpport);
-
- httpAdapterLoaded = true;
-
- } catch( Throwable t ) {
- httpServerName=null;
- log.error( "Can't load the MX4J http adapter ", t );
- }
- }
-
- if ((httpport != -1) && (!httpAdapterLoaded) && classExists("mx4j.tools.adaptor.http.HttpAdaptor")) {
- try {
- httpServerName = registerObject("mx4j.tools.adaptor.http.HttpAdaptor",
- "Http:name=HttpAdaptor");
-
-
- if( httphost!=null )
- mserver.setAttribute(httpServerName, new Attribute("Host", httphost));
- mserver.setAttribute(httpServerName, new Attribute("Port", new Integer(httpport)));
-
- if( "none".equals(authmode) || "basic".equals(authmode) || "digest".equals(authmode) )
- mserver.setAttribute(httpServerName, new Attribute("AuthenticationMethod", authmode));
-
- if( authuser!=null && authpassword!=null )
- mserver.invoke(httpServerName, "addAuthorization",
- new Object[] {
- authuser,
- authpassword},
- new String[] { "java.lang.String", "java.lang.String" });
-
- if(useXSLTProcessor) {
- ObjectName processorName = registerObject("mx4j.tools.adaptor.http.XSLTProcessor",
- "Http:name=XSLTProcessor");
- mserver.setAttribute(httpServerName, new Attribute("ProcessorName", processorName));
- }
- // starts the server
- mserver.invoke(httpServerName, "start", null, null);
- if(log.isInfoEnabled())
- log.info( "Started MX4J console on host " + httphost + " at port " + httpport);
-
- httpAdapterLoaded = true;
-
- } catch( Throwable t ) {
- httpServerName=null;
- log.error( "Can't load the MX4J http adapter ", t );
- }
- }
-
- if ((jrmpport != -1) && classExists("mx4j.tools.naming.NamingService")) {
- try {
- jrmpServerName = registerObject("mx4j.tools.naming.NamingService",
- "Naming:name=rmiregistry");
- mserver.setAttribute(jrmpServerName, new Attribute("Port",
- new Integer(jrmpport)));
- mserver.invoke(jrmpServerName, "start", null, null);
- if(log.isInfoEnabled())
- log.info( "Creating " + jrmpServerName );
-
- // Create the JRMP adaptor
- ObjectName adaptor = registerObject("mx4j.adaptor.rmi.jrmp.JRMPAdaptor",
- "Adaptor:protocol=jrmp");
-
-
- mserver.setAttribute(adaptor, new Attribute("JNDIName", "jrmp"));
-
- mserver.invoke( adaptor, "putNamingProperty",
- new Object[] {
- javax.naming.Context.INITIAL_CONTEXT_FACTORY,
- "com.sun.jndi.rmi.registry.RegistryContextFactory"},
- new String[] { "java.lang.Object", "java.lang.Object" });
-
- String jrpmurl = "rmi://" + jrmphost + ":" + Integer.toString(jrmpport) ;
-
- mserver.invoke( adaptor, "putNamingProperty",
- new Object[] {
- javax.naming.Context.PROVIDER_URL,
- jrpmurl},
- new String[] { "java.lang.Object", "java.lang.Object" });
-
- // Registers the JRMP adaptor in JNDI and starts it
- mserver.invoke(adaptor, "start", null, null);
- if(log.isInfoEnabled())
- log.info( "Creating " + adaptor + " on host " + jrmphost + " at port " + jrmpport);
-
- jrmpAdapterLoaded = true;
-
- } catch( Exception ex ) {
- jrmpServerName = null;
- log.error( "MX4j RMI adapter not loaded: " + ex.toString());
- }
- }
-
- if ((httpport != -1) && (! httpAdapterLoaded) && classExists("com.sun.jdmk.comm.HtmlAdaptorServer")) {
- try {
- httpServerName=registerObject("com.sun.jdmk.comm.HtmlAdaptorServer",
- "Adaptor:name=html,port=" + httpport);
- if(log.isInfoEnabled())
- log.info("Registering the JMX_RI html adapter " + httpServerName + " at port " + httpport);
-
- mserver.setAttribute(httpServerName,
- new Attribute("Port", new Integer(httpport)));
-
- mserver.invoke(httpServerName, "start", null, null);
-
- httpAdapterLoaded = true;
- } catch( Throwable t ) {
- httpServerName = null;
- log.error( "Can't load the JMX_RI http adapter " + t.toString() );
- }
- }
-
- if ((!httpAdapterLoaded) && (!jrmpAdapterLoaded))
- log.warn( "No adaptors were loaded but mx.enabled was defined.");
-
- }
-
- public void destroy() {
- try {
- if(log.isInfoEnabled())
- log.info("Stoping JMX ");
-
- if( httpServerName!=null ) {
- mserver.invoke(httpServerName, "stop", null, null);
- }
- if( jrmpServerName!=null ) {
- mserver.invoke(jrmpServerName, "stop", null, null);
- }
- } catch( Throwable t ) {
- log.error( "Destroy error" + t );
- }
- }
-
- public void init() throws IOException {
- try {
- mserver = getMBeanServer();
-
- if( enabled ) {
- loadAdapter();
- }
- if( log4jEnabled) {
- try {
- registerObject("org.apache.log4j.jmx.HierarchyDynamicMBean" ,
- "log4j:hierarchy=default");
- if(log.isInfoEnabled())
- log.info("Registering the JMX hierarchy for Log4J ");
- } catch( Throwable t ) {
- if(log.isInfoEnabled())
- log.info("Can't enable log4j mx: ",t);
- }
- }
- } catch( Throwable t ) {
- log.error( "Init error", t );
- }
- }
-
- public void addHandlerCallback( JkHandler w ) {
- }
-
- MBeanServer getMBeanServer() {
- MBeanServer server;
- if( MBeanServerFactory.findMBeanServer(null).size() > 0 ) {
- server = MBeanServerFactory.findMBeanServer(null).get(0);
- } else {
- server=MBeanServerFactory.createMBeanServer();
- }
- return (server);
- }
-
-
- private static boolean classExists(String className) {
- try {
- Thread.currentThread().getContextClassLoader().loadClass(className);
- return true;
- } catch(Throwable e) {
- if (log.isInfoEnabled())
- log.info( "className [" + className + "] does not exist");
- return false;
- }
- }
-
- private ObjectName registerObject(String className, String oName)
- throws Exception {
- Class<?> c = Class.forName(className);
- Object o = c.newInstance();
- ObjectName objN = new ObjectName(oName);
- mserver.registerMBean(o, objN);
- return objN;
- }
-
- private static org.apache.juli.logging.Log log=
- org.apache.juli.logging.LogFactory.getLog( JkMX.class );
-
-
-}
-
+++ /dev/null
-/*
- * 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.jk.common;
-
-import java.io.IOException;
-
-import org.apache.jk.core.Msg;
-import org.apache.tomcat.util.buf.ByteChunk;
-import org.apache.tomcat.util.buf.MessageBytes;
-
-/**
- * A single packet for communication between the web server and the
- * container. Designed to be reused many times with no creation of
- * garbage. Understands the format of data types for these packets.
- * Can be used (somewhat confusingly) for both incoming and outgoing
- * packets.
- *
- * See Ajp14/Ajp13Packet.java.
- *
- * @author Henri Gomez [hgomez@apache.org]
- * @author Dan Milstein [danmil@shore.net]
- * @author Keith Wannamaker [Keith@Wannamaker.org]
- * @author Kevin Seguin
- * @author Costin Manolache
- */
-public class MsgAjp extends Msg {
- private static org.apache.juli.logging.Log log=
- org.apache.juli.logging.LogFactory.getLog( MsgAjp.class );
-
- // that's the original buffer size in ajp13 - otherwise we'll get interoperability problems.
- private byte buf[];
- // The current read or write position in the buffer
- private int pos;
- /**
- * This actually means different things depending on whether the
- * packet is read or write. For read, it's the length of the
- * payload (excluding the header). For write, it's the length of
- * the packet as a whole (counting the header). Oh, well.
- */
- private int len;
-
- /**
- * The maximum packet size
- */
- private int bufsize;
-
- /**
- * Constructor that takes a buffer size
- */
- public MsgAjp(int bsize) {
- if(bsize < AjpConstants.MAX_PACKET_SIZE) {
- bsize = AjpConstants.MAX_PACKET_SIZE;
- }
- bufsize = bsize;
- buf = new byte[bsize];
-
- }
-
- /**
- * No arg constructor.
- * @deprecated Use the buffer size constructor.
- */
- public MsgAjp() {
- this(AjpConstants.MAX_PACKET_SIZE);
- }
-
- /**
- * Prepare this packet for accumulating a message from the container to
- * the web server. Set the write position to just after the header
- * (but leave the length unwritten, because it is as yet unknown).
- */
- public void reset() {
- len = 4;
- pos = 4;
- }
-
- /**
- * For a packet to be sent to the web server, finish the process of
- * accumulating data and write the length of the data payload into
- * the header.
- */
- public void end() {
- len=pos;
- int dLen=len-4;
-
- buf[0] = (byte)0x41;
- buf[1] = (byte)0x42;
- buf[2]= (byte)((dLen>>>8 ) & 0xFF );
- buf[3] = (byte)(dLen & 0xFF);
- }
-
- public byte[] getBuffer() {
- return buf;
- }
-
- public int getLen() {
- return len;
- }
-
- // ============ Data Writing Methods ===================
-
- /**
- * Add an int.
- *
- * @param val The integer to write.
- */
- public void appendInt( int val ) {
- buf[pos++] = (byte) ((val >>> 8) & 0xFF);
- buf[pos++] = (byte) (val & 0xFF);
- }
-
- public void appendByte( int val ) {
- buf[pos++] = (byte)val;
- }
-
- public void appendLongInt( int val ) {
- buf[pos++] = (byte) ((val >>> 24) & 0xFF);
- buf[pos++] = (byte) ((val >>> 16) & 0xFF);
- buf[pos++] = (byte) ((val >>> 8) & 0xFF);
- buf[pos++] = (byte) (val & 0xFF);
- }
-
- /**
- * Write a String out at the current write position. Strings are
- * encoded with the length in two bytes first, then the string, and
- * then a terminating \0 (which is <B>not</B> included in the
- * encoded length). The terminator is for the convenience of the C
- * code, where it saves a round of copying. A null string is
- * encoded as a string with length 0.
- */
- public void appendBytes(MessageBytes mb) throws IOException {
- if(mb==null || mb.isNull() ) {
- appendInt( 0);
- appendByte(0);
- return;
- }
-
- // XXX Convert !!
- ByteChunk bc= mb.getByteChunk();
- appendByteChunk(bc);
- }
-
- public void appendByteChunk(ByteChunk bc) throws IOException {
- if(bc==null) {
- log.error("appendByteChunk() null");
- appendInt( 0);
- appendByte(0);
- return;
- }
-
- byte[] bytes = bc.getBytes();
- int start=bc.getStart();
- int length = bc.getLength();
- appendInt( length );
- cpBytes(bytes, start, length);
- appendByte(0);
- }
-
- /**
- * Copy a chunk of bytes into the packet, starting at the current
- * write position. The chunk of bytes is encoded with the length
- * in two bytes first, then the data itself, and finally a
- * terminating \0 (which is <B>not</B> included in the encoded
- * length).
- *
- * @param b The array from which to copy bytes.
- * @param off The offset into the array at which to start copying
- * @param numBytes The number of bytes to copy.
- */
- public void appendBytes( byte b[], int off, int numBytes ) {
- appendInt( numBytes );
- cpBytes( b, off, numBytes );
- appendByte(0);
- }
-
- private void cpBytes( byte b[], int off, int numBytes ) {
- if( pos + numBytes >= buf.length ) {
- log.error("Buffer overflow: buffer.len=" + buf.length + " pos=" +
- pos + " data=" + numBytes );
- dump("Overflow/coBytes");
- log.error( "Overflow ", new Throwable());
- return;
- }
- System.arraycopy( b, off, buf, pos, numBytes);
- pos += numBytes;
- // buf[pos + numBytes] = 0; // Terminating \0
- }
-
-
-
- // ============ Data Reading Methods ===================
-
- /**
- * Read an integer from packet, and advance the read position past
- * it. Integers are encoded as two unsigned bytes with the
- * high-order byte first, and, as far as I can tell, in
- * little-endian order within each byte.
- */
- public int getInt() {
- int b1 = buf[pos++] & 0xFF; // No swap, Java order
- int b2 = buf[pos++] & 0xFF;
-
- return (b1<<8) + b2;
- }
-
- public int peekInt() {
- int b1 = buf[pos] & 0xFF; // No swap, Java order
- int b2 = buf[pos+1] & 0xFF;
-
- return (b1<<8) + b2;
- }
-
- public byte getByte() {
- byte res = buf[pos++];
- return res;
- }
-
- public byte peekByte() {
- byte res = buf[pos];
- return res;
- }
-
- public void getBytes(MessageBytes mb) {
- int length = getInt();
- if( (length == 0xFFFF) || (length == -1) ) {
- mb.recycle();
- return;
- }
- mb.setBytes( buf, pos, length );
- mb.getCharChunk().recycle();
- pos += length;
- pos++; // Skip the terminating \0
- }
-
- /**
- * Copy a chunk of bytes from the packet into an array and advance
- * the read position past the chunk. See appendBytes() for details
- * on the encoding.
- *
- * @return The number of bytes copied.
- */
- public int getBytes(byte dest[]) {
- int length = getInt();
- if( length > buf.length ) {
- // XXX Should be if(pos + length > buff.legth)?
- log.error("getBytes() buffer overflow " + length + " " + buf.length );
- }
-
- if( (length == 0xFFFF) || (length == -1) ) {
- log.info("Null string " + length);
- return 0;
- }
-
- System.arraycopy( buf, pos, dest, 0, length );
- pos += length;
- pos++; // Skip terminating \0 XXX I believe this is wrong but harmless
- return length;
- }
-
- /**
- * Read a 32 bits integer from packet, and advance the read position past
- * it. Integers are encoded as four unsigned bytes with the
- * high-order byte first, and, as far as I can tell, in
- * little-endian order within each byte.
- */
- public int getLongInt() {
- int b1 = buf[pos++] & 0xFF; // No swap, Java order
- b1 <<= 8;
- b1 |= (buf[pos++] & 0xFF);
- b1 <<= 8;
- b1 |= (buf[pos++] & 0xFF);
- b1 <<=8;
- b1 |= (buf[pos++] & 0xFF);
- return b1;
- }
-
- public int getHeaderLength() {
- return 4;
- }
-
- public int processHeader() {
- pos = 0;
- int mark = getInt();
- len = getInt();
-
- if( mark != 0x1234 && mark != 0x4142 ) {
- // XXX Logging
- log.error("BAD packet signature " + mark);
- dump( "In: " );
- return -1;
- }
-
- if( log.isDebugEnabled() )
- log.debug( "Received " + len + " " + buf[0] );
- return len;
- }
-
- public void dump(String msg) {
- if( log.isDebugEnabled() )
- log.debug( msg + ": " + buf + " " + pos +"/" + (len + 4));
- int max=pos;
- if( len + 4 > pos )
- max=len+4;
- if( max >1000 ) max=1000;
- if( log.isDebugEnabled() )
- for( int j=0; j < max; j+=16 )
- log.debug( hexLine( buf, j, len ));
-
- }
-
- /* -------------------- Utilities -------------------- */
- // XXX Move to util package
-
- public static String hexLine( byte buf[], int start, int len ) {
- StringBuffer sb=new StringBuffer();
- for( int i=start; i< start+16 ; i++ ) {
- if( i < len + 4)
- sb.append( hex( buf[i] ) + " ");
- else
- sb.append( " " );
- }
- sb.append(" | ");
- for( int i=start; i < start+16 && i < len + 4; i++ ) {
- if( ! Character.isISOControl( (char)buf[i] ))
- sb.append( new Character((char)buf[i]) );
- else
- sb.append( "." );
- }
- return sb.toString();
- }
-
- private static String hex( int x ) {
- // if( x < 0) x=256 + x;
- String h=Integer.toHexString( x );
- if( h.length() == 1 ) h = "0" + h;
- return h.substring( h.length() - 2 );
- }
-
-}
+++ /dev/null
-/*
- * 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.jk.common;
-
-import java.io.IOException;
-
-import org.apache.jk.core.JkHandler;
-import org.apache.jk.core.Msg;
-import org.apache.jk.core.MsgContext;
-import org.apache.jk.core.WorkerEnv;
-import org.apache.tomcat.util.buf.MessageBytes;
-
-
-/** A dummy worker, will just send back a dummy response.
- * Used for testing and tunning.
- */
-public class WorkerDummy extends JkHandler
-{
- public WorkerDummy()
- {
- String msg="HelloWorld";
- byte b[]=msg.getBytes();
- body.setBytes(b, 0, b.length);
- }
-
- /* ==================== Start/stop ==================== */
-
- /** Initialize the worker. After this call the worker will be
- * ready to accept new requests.
- */
- public void init() throws IOException {
- headersMsgNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "headerMsg" );
- }
-
- MessageBytes body=MessageBytes.newInstance();
- private int headersMsgNote;
-
- public int invoke( Msg in, MsgContext ep )
- throws IOException
- {
- MsgAjp msg=(MsgAjp)ep.getNote( headersMsgNote );
- if( msg==null ) {
- msg=new MsgAjp();
- ep.setNote( headersMsgNote, msg );
- }
-
- msg.reset();
- msg.appendByte(AjpConstants.JK_AJP13_SEND_HEADERS);
- msg.appendInt(200);
- msg.appendBytes(null);
-
- msg.appendInt(0);
-
- ep.setType( JkHandler.HANDLE_SEND_PACKET );
- ep.getSource().invoke( msg, ep );
- // msg.dump("out:" );
-
- msg.reset();
- msg.appendByte( AjpConstants.JK_AJP13_SEND_BODY_CHUNK);
- msg.appendInt( body.getLength() );
- msg.appendBytes( body );
-
-
- ep.getSource().invoke(msg, ep);
-
- msg.reset();
- msg.appendByte( AjpConstants.JK_AJP13_END_RESPONSE );
- msg.appendInt( 1 );
-
- ep.getSource().invoke(msg, ep );
- return OK;
- }
-
- private static final int dL=0;
-}
-
+++ /dev/null
-/*
- * 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.jk.config;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Date;
-import java.util.Hashtable;
-
-import org.apache.catalina.Context;
-import org.apache.catalina.Host;
-
-/* The idea is to keep all configuration in server.xml and
- the normal apache config files. We don't want people to
- touch apache ( or IIS, NES ) config files unless they
- want to and know what they're doing ( better than we do :-).
-
- One nice feature ( if someone sends it ) would be to
- also edit httpd.conf to add the include.
-
- We'll generate a number of configuration files - this one
- is trying to generate a native apache config file.
-
- Some web.xml mappings do not "map" to server configuration - in
- this case we need to fallback to forward all requests to tomcat.
-
- Ajp14 will add to that the posibility to have tomcat and
- apache on different machines, and many other improvements -
- but this should also work for Ajp12, Ajp13 and Jni.
-
-*/
-
-/**
- Generates automatic apache mod_jk configurations based on
- the Tomcat server.xml settings and the war contexts
- initialized during startup.
- <p>
- This config interceptor is enabled by inserting an ApacheConfig
- <code>Listener</code> in
- the server.xml file like so:
- <pre>
- * < Server ... >
- * ...
- * <Listener className=<b>org.apache.ajp.tomcat4.config.ApacheConfig</b>
- * <i>options</i> />
- * ...
- * < /Server >
- </pre>
- where <i>options</i> can include any of the following attributes:
- <ul>
- <li><b>configHome</b> - default parent directory for the following paths.
- If not set, this defaults to TOMCAT_HOME. Ignored
- whenever any of the following paths is absolute.
- </li>
- <li><b>jkConfig</b> - path to use for writing Apache mod_jk conf file. If
- not set, defaults to
- "conf/auto/mod_jk.conf".</li>
- <li><b>workersConfig</b> - path to workers.properties file used by
- mod_jk. If not set, defaults to
- "conf/jk/workers.properties".</li>
- <li><b>modJk</b> - path to Apache mod_jk plugin file. If not set,
- defaults to "modules/mod_jk.dll" on windows,
- "modules/mod_jk.nlm" on netware, and
- "libexec/mod_jk.so" everywhere else.</li>
- <li><b>jkLog</b> - path to log file to be used by mod_jk.</li>
- <li><b>jkDebug</b> - JK Loglevel setting. May be debug, info, error, or emerg.
- If not set, defaults to emerg.</li>
- <li><b>jkWorker</b> The desired worker. Must be set to one of the workers
- defined in the workers.properties file. "ajp12", "ajp13"
- or "inprocess" are the workers found in the default
- workers.properties file. If not specified, defaults
- to "ajp13" if an Ajp13Interceptor is in use, otherwise
- it defaults to "ajp12".</li>
- <li><b>forwardAll</b> - If true, forward all requests to Tomcat. This helps
- insure that all the behavior configured in the web.xml
- file functions correctly. If false, let Apache serve
- static resources. The default is true.
- Warning: When false, some configuration in
- the web.xml may not be duplicated in Apache.
- Review the mod_jk conf file to see what
- configuration is actually being set in Apache.</li>
- <li><b>noRoot</b> - If true, the root context is not mapped to
- Tomcat. If false and forwardAll is true, all requests
- to the root context are mapped to Tomcat. If false and
- forwardAll is false, only JSP and servlets requests to
- the root context are mapped to Tomcat. When false,
- to correctly serve Tomcat's root context you must also
- modify the DocumentRoot setting in Apache's httpd.conf
- file to point to Tomcat's root context directory.
- Otherwise some content, such as Apache's index.html,
- will be served by Apache before mod_jk gets a chance
- to claim the request and pass it to Tomcat.
- The default is true.</li>
- </ul>
- <p>
- @author Costin Manolache
- @author Larry Isaacs
- @author Mel Martinez
- @author Bill Barker
- */
-public class ApacheConfig extends BaseJkConfig {
-
- private static org.apache.juli.logging.Log log =
- org.apache.juli.logging.LogFactory.getLog(ApacheConfig.class);
-
- /** default path to mod_jk .conf location */
- public static final String MOD_JK_CONFIG = "conf/auto/mod_jk.conf";
- /** default path to workers.properties file
- This should be also auto-generated from server.xml.
- */
- public static final String WORKERS_CONFIG = "conf/jk/workers.properties";
- /** default mod_jk log file location */
- public static final String JK_LOG_LOCATION = "logs/mod_jk.log";
- /** default location of mod_jk Apache plug-in. */
- public static final String MOD_JK;
-
- //set up some defaults based on OS type
- static{
- String os = System.getProperty("os.name").toLowerCase();
- if(os.indexOf("windows")>=0){
- MOD_JK = "modules/mod_jk.dll";
- }else if(os.indexOf("netware")>=0){
- MOD_JK = "modules/mod_jk.nlm";
- }else{
- MOD_JK = "libexec/mod_jk.so";
- }
- }
-
- private File jkConfig = null;
- private File modJk = null;
-
- // ssl settings
- private boolean sslExtract=true;
- private String sslHttpsIndicator="HTTPS";
- private String sslSessionIndicator="SSL_SESSION_ID";
- private String sslCipherIndicator="SSL_CIPHER";
- private String sslCertsIndicator="SSL_CLIENT_CERT";
-
- Hashtable<String, String> NamedVirtualHosts=null;
-
- public ApacheConfig() {
- }
-
- //-------------------- Properties --------------------
-
- /**
- set the path to the output file for the auto-generated
- mod_jk configuration file. If this path is relative
- then it will be resolved absolutely against
- the getConfigHome() path.
- <p>
- @param path String path to a file
- */
- public void setJkConfig(String path){
- jkConfig= (path==null)?null:new File(path);
- }
-
- /**
- set the path to the mod_jk Apache Module
- @param path String path to a file
- */
- public void setModJk(String path){
- modJk=( path==null?null:new File(path));
- }
-
- /** By default mod_jk is configured to collect SSL information from
- the apache environment and send it to the Tomcat workers. The
- problem is that there are many SSL solutions for Apache and as
- a result the environment variable names may change.
-
- The following JK related SSL configureation
- can be used to customize mod_jk's SSL behaviour.
-
- Should mod_jk send SSL information to Tomact (default is On)
- */
- public void setExtractSSL( boolean sslMode ) {
- this.sslExtract=sslMode;
- }
-
- /** What is the indicator for SSL (default is HTTPS)
- */
- public void setHttpsIndicator( String s ) {
- sslHttpsIndicator=s;
- }
-
- /**What is the indicator for SSL session (default is SSL_SESSION_ID)
- */
- public void setSessionIndicator( String s ) {
- sslSessionIndicator=s;
- }
-
- /**What is the indicator for client SSL cipher suit (default is SSL_CIPHER)
- */
- public void setCipherIndicator( String s ) {
- sslCipherIndicator=s;
- }
-
- /** What is the indicator for the client SSL certificated(default
- is SSL_CLIENT_CERT
- */
- public void setCertsIndicator( String s ) {
- sslCertsIndicator=s;
- }
-
- // -------------------- Initialize/guess defaults --------------------
-
- /** Initialize defaults for properties that are not set
- explicitely
- */
- protected void initProperties() {
- super.initProperties();
-
- jkConfig= getConfigFile( jkConfig, configHome, MOD_JK_CONFIG);
- workersConfig=getConfigFile( workersConfig, configHome,
- WORKERS_CONFIG);
- if( modJk == null )
- modJk=new File(MOD_JK);
- else
- modJk=getConfigFile( modJk, configHome, MOD_JK );
- jkLog=getConfigFile( jkLog, configHome, JK_LOG_LOCATION);
- }
- // -------------------- Generate config --------------------
-
- protected PrintWriter getWriter() throws IOException {
- String abJkConfig = jkConfig.getAbsolutePath();
- return new PrintWriter(new FileWriter(abJkConfig, append));
- }
-
-
- // -------------------- Config sections --------------------
-
- /** Generate the loadModule and general options
- */
- protected boolean generateJkHead(PrintWriter mod_jk)
- {
-
- mod_jk.println("########## Auto generated on " + new Date() +
- "##########" );
- mod_jk.println();
-
- // Fail if mod_jk not found, let the user know the problem
- // instead of running into problems later.
- if( ! modJk.exists() ) {
- log.info( "mod_jk location: " + modJk );
- log.info( "Make sure it is installed corectly or " +
- " set the config location" );
- log.info( "Using <Listener className=\""+getClass().getName()+"\" modJk=\"PATH_TO_MOD_JK.SO_OR_DLL\" />" );
- }
-
- // Verify the file exists !!
- mod_jk.println("<IfModule !mod_jk.c>");
- mod_jk.println(" LoadModule jk_module \""+
- modJk.toString().replace('\\','/') +
- "\"");
- mod_jk.println("</IfModule>");
- mod_jk.println();
-
-
- // Fail if workers file not found, let the user know the problem
- // instead of running into problems later.
- if( ! workersConfig.exists() ) {
- log.warn( "Can't find workers.properties at " + workersConfig );
- log.warn( "Please install it in the default location or " +
- " set the config location" );
- log.warn( "Using <Listener className=\"" + getClass().getName() + "\" workersConfig=\"FULL_PATH\" />" );
- return false;
- }
-
- mod_jk.println("JkWorkersFile \""
- + workersConfig.toString().replace('\\', '/')
- + "\"");
-
- mod_jk.println("JkLogFile \""
- + jkLog.toString().replace('\\', '/')
- + "\"");
- mod_jk.println();
-
- if( jkDebug != null ) {
- mod_jk.println("JkLogLevel " + jkDebug);
- mod_jk.println();
- }
- return true;
- }
-
- protected void generateVhostHead(Host host, PrintWriter mod_jk) {
-
- mod_jk.println();
- String vhostip = host.getName();
- String vhost = vhostip;
- int ppos = vhost.indexOf(":");
- if(ppos >= 0)
- vhost = vhost.substring(0,ppos);
-
- mod_jk.println("<VirtualHost "+ vhostip + ">");
- mod_jk.println(" ServerName " + vhost );
- String [] aliases=host.findAliases();
- if( aliases.length > 0 ) {
- mod_jk.print(" ServerAlias " );
- for( int ii=0; ii < aliases.length ; ii++) {
- mod_jk.print( aliases[ii] + " " );
- }
- mod_jk.println();
- }
- indent=" ";
- }
-
- protected void generateVhostTail(Host host, PrintWriter mod_jk) {
- mod_jk.println("</VirtualHost>");
- indent="";
- }
-
- protected void generateSSLConfig(PrintWriter mod_jk) {
- if( ! sslExtract ) {
- mod_jk.println("JkExtractSSL Off");
- }
- if( ! "HTTPS".equalsIgnoreCase( sslHttpsIndicator ) ) {
- mod_jk.println("JkHTTPSIndicator " + sslHttpsIndicator);
- }
- if( ! "SSL_SESSION_ID".equalsIgnoreCase( sslSessionIndicator )) {
- mod_jk.println("JkSESSIONIndicator " + sslSessionIndicator);
- }
- if( ! "SSL_CIPHER".equalsIgnoreCase( sslCipherIndicator )) {
- mod_jk.println("JkCIPHERIndicator " + sslCipherIndicator);
- }
- if( ! "SSL_CLIENT_CERT".equalsIgnoreCase( sslCertsIndicator )) {
- mod_jk.println("JkCERTSIndicator " + sslCertsIndicator);
- }
-
- mod_jk.println();
- }
-
- // -------------------- Forward all mode --------------------
- String indent="";
-
- /** Forward all requests for a context to tomcat.
- The default.
- */
- protected void generateStupidMappings(Context context,
- PrintWriter mod_jk )
- {
- String ctxPath = context.getPath();
- if(ctxPath == null)
- return;
-
- String nPath=("".equals(ctxPath)) ? "/" : ctxPath;
-
- mod_jk.println();
- mod_jk.println(indent + "JkMount " + nPath + " " + jkWorker );
- if( "".equals(ctxPath) ) {
- mod_jk.println(indent + "JkMount " + nPath + "* " + jkWorker );
- if ( context.getParent() instanceof Host ) {
- mod_jk.println(indent + "DocumentRoot \"" +
- getApacheDocBase(context) + "\"");
- } else {
- mod_jk.println(indent +
- "# To avoid Apache serving root welcome files from htdocs, update DocumentRoot");
- mod_jk.println(indent +
- "# to point to: \"" + getApacheDocBase(context) + "\"");
- }
-
- } else {
- mod_jk.println(indent + "JkMount " + nPath + "/* " + jkWorker );
- }
- }
-
- // -------------------- Apache serves static mode --------------------
- // This is not going to work for all apps. We fall back to stupid mode.
-
- protected void generateContextMappings(Context context, PrintWriter mod_jk )
- {
- String ctxPath = context.getPath();
- Host vhost = getHost(context);
-
- if( noRoot && "".equals(ctxPath) ) {
- log.debug("Ignoring root context in non-forward-all mode ");
- return;
- }
-
- mod_jk.println();
- mod_jk.println(indent + "#################### " +
- ((vhost!=null ) ? vhost.getName() + ":" : "" ) +
- (("".equals(ctxPath)) ? "/" : ctxPath ) +
- " ####################" );
- mod_jk.println();
- // Dynamic /servet pages go to Tomcat
-
- generateStaticMappings( context, mod_jk );
-
- // InvokerInterceptor - it doesn't have a container,
- // but it's implemented using a special module.
-
- // XXX we need to better collect all mappings
-
- if(context.getLoginConfig() != null) {
- String loginPage = context.getLoginConfig().getLoginPage();
- if(loginPage != null) {
- int lpos = loginPage.lastIndexOf("/");
- String jscurl = loginPage.substring(0,lpos+1) + "j_security_check";
- addMapping( ctxPath, jscurl, mod_jk);
- }
- }
- String [] servletMaps = context.findServletMappings();
- for(int ii=0; ii < servletMaps.length; ii++) {
- addMapping( ctxPath, servletMaps[ii] , mod_jk );
- }
- }
-
- /** Add an Apache extension mapping.
- */
- protected boolean addExtensionMapping( String ctxPath, String ext,
- PrintWriter mod_jk )
- {
- if( log.isDebugEnabled() )
- log.debug( "Adding extension map for " + ctxPath + "/*." + ext );
- mod_jk.println(indent + "JkMount " + ctxPath + "/*." + ext
- + " " + jkWorker);
- return true;
- }
-
-
- /** Add a fulling specified Appache mapping.
- */
- protected boolean addMapping( String fullPath, PrintWriter mod_jk ) {
- if( log.isDebugEnabled() )
- log.debug( "Adding map for " + fullPath );
- mod_jk.println(indent + "JkMount " + fullPath + " " + jkWorker );
- return true;
- }
- /** Add a partially specified Appache mapping.
- */
- protected boolean addMapping( String ctxP, String ext, PrintWriter mod_jk ) {
- if( log.isDebugEnabled() )
- log.debug( "Adding map for " + ext );
- if(! ext.startsWith("/") )
- ext = "/" + ext;
- if(ext.length() > 1)
- mod_jk.println(indent + "JkMount " + ctxP + ext+ " " + jkWorker );
- return true;
- }
-
- private void generateWelcomeFiles(Context context, PrintWriter mod_jk ) {
- String wf[]=context.findWelcomeFiles();
- if( wf==null || wf.length == 0 )
- return;
- mod_jk.print(indent + " DirectoryIndex ");
- for( int i=0; i<wf.length ; i++ ) {
- mod_jk.print( wf[i] + " " );
- }
- mod_jk.println();
- }
-
- /** Mappings for static content. XXX need to add welcome files,
- * mime mappings ( all will be handled by Mime and Static modules of
- * apache ).
- */
- private void generateStaticMappings(Context context, PrintWriter mod_jk ) {
- String ctxPath = context.getPath();
-
- // Calculate the absolute path of the document base
- String docBase = getApacheDocBase(context);
-
- if( !"".equals(ctxPath) ) {
- // Static files will be served by Apache
- mod_jk.println(indent + "# Static files ");
- mod_jk.println(indent + "Alias " + ctxPath + " \"" + docBase + "\"");
- mod_jk.println();
- } else {
- if ( getHost(context) != null ) {
- mod_jk.println(indent + "DocumentRoot \"" +
- getApacheDocBase(context) + "\"");
- } else {
- // For root context, ask user to update DocumentRoot setting.
- // Using "Alias / " interferes with the Alias for other contexts.
- mod_jk.println(indent +
- "# Be sure to update DocumentRoot");
- mod_jk.println(indent +
- "# to point to: \"" + docBase + "\"");
- }
- }
- mod_jk.println(indent + "<Directory \"" + docBase + "\">");
- mod_jk.println(indent + " Options Indexes FollowSymLinks");
-
- generateWelcomeFiles(context, mod_jk);
-
- // XXX XXX Here goes the Mime types and welcome files !!!!!!!!
- mod_jk.println(indent + "</Directory>");
- mod_jk.println();
-
-
- // Deny serving any files from WEB-INF
- mod_jk.println();
- mod_jk.println(indent +
- "# Deny direct access to WEB-INF and META-INF");
- mod_jk.println(indent + "#");
- mod_jk.println(indent + "<Location \"" + ctxPath + "/WEB-INF/*\">");
- mod_jk.println(indent + " AllowOverride None");
- mod_jk.println(indent + " deny from all");
- mod_jk.println(indent + "</Location>");
- // Deny serving any files from META-INF
- mod_jk.println();
- mod_jk.println(indent + "<Location \"" + ctxPath + "/META-INF/*\">");
- mod_jk.println(indent + " AllowOverride None");
- mod_jk.println(indent + " deny from all");
- mod_jk.println(indent + "</Location>");
- if (File.separatorChar == '\\') {
- mod_jk.println(indent + "#");
- mod_jk.println(indent +
- "# Use Directory too. On Windows, Location doesn't"
- + " work unless case matches");
- mod_jk.println(indent + "#");
- mod_jk.println(indent +
- "<Directory \"" + docBase + "/WEB-INF/\">");
- mod_jk.println(indent + " AllowOverride None");
- mod_jk.println(indent + " deny from all");
- mod_jk.println(indent + "</Directory>");
- mod_jk.println();
- mod_jk.println(indent +
- "<Directory \"" + docBase + "/META-INF/\">");
- mod_jk.println(indent + " AllowOverride None");
- mod_jk.println(indent + " deny from all");
- mod_jk.println(indent + "</Directory>");
- }
- mod_jk.println();
- }
-
- // -------------------- Utils --------------------
-
- private String getApacheDocBase(Context context)
- {
- // Calculate the absolute path of the document base
- String docBase = getAbsoluteDocBase(context);
- if (File.separatorChar == '\\') {
- // use separator preferred by Apache
- docBase = docBase.replace('\\','/');
- }
- return docBase;
- }
-
-}
+++ /dev/null
-/*
- * 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.jk.config;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
-
-import org.apache.catalina.Container;
-import org.apache.catalina.Context;
-import org.apache.catalina.Engine;
-import org.apache.catalina.Host;
-import org.apache.catalina.Lifecycle;
-import org.apache.catalina.LifecycleEvent;
-import org.apache.catalina.LifecycleListener;
-import org.apache.catalina.Server;
-
-
-/**
- Base class for automatic jk based configurations based on
- the Tomcat server.xml settings and the war contexts
- initialized during startup.
- <p>
- This config interceptor is enabled by inserting a Config
- element in the <b><ContextManager></b> tag body inside
- the server.xml file like so:
- <pre>
- * < ContextManager ... >
- * ...
- * <<b>???Config</b> <i>options</i> />
- * ...
- * < /ContextManager >
- </pre>
- where <i>options</i> can include any of the following attributes:
- <ul>
- <li><b>configHome</b> - default parent directory for the following paths.
- If not set, this defaults to TOMCAT_HOME. Ignored
- whenever any of the following paths is absolute.
- </li>
- <li><b>workersConfig</b> - path to workers.properties file used by
- jk connector. If not set, defaults to
- "conf/jk/workers.properties".</li>
- <li><b>jkLog</b> - path to log file to be used by jk connector.</li>
- <li><b>jkDebug</b> - Loglevel setting. May be debug, info, error, or emerg.
- If not set, defaults to emerg.</li>
- <li><b>jkWorker</b> The desired worker. Must be set to one of the workers
- defined in the workers.properties file. "ajp12", "ajp13"
- or "inprocess" are the workers found in the default
- workers.properties file. If not specified, defaults
- to "ajp13" if an Ajp13Interceptor is in use, otherwise
- it defaults to "ajp12".</li>
- <li><b>forwardAll</b> - If true, forward all requests to Tomcat. This helps
- insure that all the behavior configured in the web.xml
- file functions correctly. If false, let Apache serve
- static resources. The default is true.
- Warning: When false, some configuration in
- the web.xml may not be duplicated in Apache.
- Review the mod_jk conf file to see what
- configuration is actually being set in Apache.</li>
- <li><b>noRoot</b> - If true, the root context is not mapped to
- Tomcat. If false and forwardAll is true, all requests
- to the root context are mapped to Tomcat. If false and
- forwardAll is false, only JSP and servlets requests to
- the root context are mapped to Tomcat. When false,
- to correctly serve Tomcat's root context you may also
- need to modify the web server to point it's home
- directory to Tomcat's root context directory.
- Otherwise some content, such as the root index.html,
- may be served by the web server before the connector
- gets a chance to claim the request and pass it to Tomcat.
- The default is true.</li>
- </ul>
- <p>
- @author Costin Manolache
- @author Larry Isaacs
- @author Bill Barker
- @version $Revision$
- */
-public class BaseJkConfig implements LifecycleListener {
- private static org.apache.juli.logging.Log log =
- org.apache.juli.logging.LogFactory.getLog(BaseJkConfig.class);
-
- protected File configHome = null;
- protected File workersConfig = null;
-
- protected File jkLog = null;
- protected String jkDebug="emerg";
- protected String jkWorker = "ajp13";
-
- protected boolean noRoot=true;
- protected boolean forwardAll=true;
-
- protected String tomcatHome;
- protected boolean regenerate=false;
- protected boolean append=false;
- protected boolean legacy=true;
-
- // -------------------- Tomcat callbacks --------------------
-
-
- // Auto-config should be able to react to dynamic config changes,
- // and regenerate the config.
-
- /**
- * Generate the configuration - only when the server is
- * completely initialized ( before starting )
- */
- public void lifecycleEvent(LifecycleEvent evt) {
- if(Lifecycle.START_EVENT.equals(evt.getType())) {
- execute( evt );
- }
- }
-
- /**
- * Generate configuration files. Override with method to generate
- * web server specific configuration.
- */
- public void execute(LifecycleEvent evt) {
- initProperties();
- PrintWriter mod_jk = null;
- try {
- mod_jk = getWriter();
- } catch(IOException iex) {
- log.warn("Unable to open config file");
- return;
- }
- Lifecycle who = evt.getLifecycle();
- if( who instanceof Server ) {
- executeServer((Server)who, mod_jk);
- } else if(who instanceof Engine) {
- executeEngine((Engine)who, mod_jk);
- } else if ( who instanceof Host ) {
- executeHost((Host)who, mod_jk);
- } else if( who instanceof Context ) {
- executeContext((Context)who, mod_jk);
- }
- mod_jk.close();
- }
- /**
- * Generate configuration files. Override with method to generate
- * web server specific configuration.
- */
- public void executeServer(Server svr, PrintWriter mod_jk) {
- if(! append ) {
- if( ! generateJkHead(mod_jk) )
- return;
- generateSSLConfig(mod_jk);
- generateJkTail(mod_jk);
- }
- }
-
- /**
- * Generate SSL options
- */
- protected void generateSSLConfig(PrintWriter mod_jk) {
- }
-
- /**
- * Generate general options
- */
- protected boolean generateJkHead(PrintWriter mod_jk) {
- return true;
- }
-
- /**
- * Generate general options
- */
- protected void generateJkTail(PrintWriter mod_jk) {
- }
-
- /**
- * Generate Virtual Host start
- */
- protected void generateVhostHead(Host host, PrintWriter mod_jk) {
- }
-
- /**
- * Generate Virtual Host end
- */
- protected void generateVhostTail(Host host, PrintWriter mod_jk) {
- }
-
- /**
- * Generate configuration files. Override with method to generate
- * web server specific configuration.
- */
- protected void executeEngine(Engine egn, PrintWriter mod_jk) {
- if(egn.getJvmRoute() != null) {
- jkWorker = egn.getJvmRoute();
- }
- executeServer(egn.getService().getServer(), mod_jk);
- Container [] children = egn.findChildren();
- for(int ii=0; ii < children.length; ii++) {
- if( children[ii] instanceof Host ) {
- executeHost((Host)children[ii], mod_jk);
- } else if( children[ii] instanceof Context ) {
- executeContext((Context)children[ii], mod_jk);
- }
- }
- }
- /**
- * Generate configuration files. Override with method to generate
- * web server specific configuration.
- */
- protected void executeHost(Host hst, PrintWriter mod_jk) {
- generateVhostHead(hst, mod_jk);
- Container [] children = hst.findChildren();
- for(int ii=0; ii < children.length; ii++) {
- if(children[ii] instanceof Context) {
- executeContext((Context)children[ii],mod_jk);
- }
- }
- generateVhostTail(hst, mod_jk);
- }
- /**
- * executes the ApacheConfig interceptor. This method generates apache
- * configuration files for use with mod_jk.
- * @param context a Context object.
- * @param mod_jk Writer for output.
- */
- public void executeContext(Context context, PrintWriter mod_jk){
-
- if(context.getPath().length() > 0 || ! noRoot ) {
- String docRoot = context.getServletContext().getRealPath("/");
- if( forwardAll || docRoot == null)
- generateStupidMappings( context, mod_jk );
- else
- generateContextMappings( context, mod_jk);
- }
- }
-
- protected void generateStupidMappings(Context context, PrintWriter mod_jk){
- }
- protected void generateContextMappings(Context context, PrintWriter mod_jk){
- }
-
- /**
- * Get the output Writer. Override with method to generate
- * web server specific configuration.
- */
- protected PrintWriter getWriter() throws IOException {
- return null;
- }
-
- /**
- * Get the host associated with this Container (if any).
- */
- protected Host getHost(Container child) {
- while(child != null && ! (child instanceof Host) ) {
- child = child.getParent();
- }
- return (Host)child;
- }
-
- //-------------------- Properties --------------------
-
- /**
- * Append to config file.
- * Set to <code>true</code> if the config information should be
- * appended.
- */
- public void setAppend(boolean apnd) {
- append = apnd;
- }
-
- /**
- * If false, we'll try to generate a config that will
- * let apache serve static files.
- * The default is true, forward all requests in a context
- * to tomcat.
- */
- public void setForwardAll( boolean b ) {
- forwardAll=b;
- }
-
- /**
- * Special option - do not generate mappings for the ROOT
- * context. The default is true, and will not generate the mappings,
- * not redirecting all pages to tomcat (since /* matches everything).
- * This means that the web server's root remains intact but isn't
- * completely servlet/JSP enabled. If the ROOT webapp can be configured
- * with the web server serving static files, there's no problem setting
- * this option to false. If not, then setting it true means the web
- * server will be out of picture for all requests.
- */
- public void setNoRoot( boolean b ) {
- noRoot=b;
- }
-
- /**
- * set a path to the parent directory of the
- * conf folder. That is, the parent directory
- * within which path setters would be resolved against,
- * if relative. For example if ConfigHome is set to "/home/tomcat"
- * and regConfig is set to "conf/mod_jk.conf" then the resulting
- * path used would be:
- * "/home/tomcat/conf/mod_jk.conf".</p>
- * <p>
- * However, if the path is set to an absolute path,
- * this attribute is ignored.
- * <p>
- * If not set, execute() will set this to TOMCAT_HOME.
- * @param dir - path to a directory
- */
- public void setConfigHome(String dir){
- if( dir==null ) return;
- File f=new File(dir);
- if(!f.isDirectory()){
- throw new IllegalArgumentException(
- "BaseConfig.setConfigHome(): "+
- "Configuration Home must be a directory! : "+dir);
- }
- configHome = f;
- }
-
- /**
- * set a path to the workers.properties file.
- * @param path String path to workers.properties file
- */
- public void setWorkersConfig(String path){
- workersConfig= (path==null?null:new File(path));
- }
-
- /**
- * set the path to the log file
- * @param path String path to a file
- */
- public void setJkLog(String path){
- jkLog = ( path==null ? null : new File(path));
- }
-
- /**
- * Set the verbosity level
- * ( use debug, error, etc. ) If not set, no log is written.
- */
- public void setJkDebug( String level ) {
- jkDebug=level;
- }
-
- /**
- * Sets the JK worker.
- * @param worker The worker
- */
- public void setJkWorker(String worker){
- jkWorker = worker;
- }
-
- public void setLegacy(boolean legacy) {
- this.legacy = legacy;
- }
-
- // -------------------- Initialize/guess defaults --------------------
-
- /**
- * Initialize defaults for properties that are not set
- * explicitely
- */
- protected void initProperties() {
- tomcatHome = System.getProperty("catalina.home");
- File tomcatDir = new File(tomcatHome);
- if(configHome==null){
- configHome=tomcatDir;
- }
- }
-
- // -------------------- Config Utils --------------------
-
-
- /**
- * Add an extension mapping. Override with method to generate
- * web server specific configuration
- */
- protected boolean addExtensionMapping( String ctxPath, String ext,
- PrintWriter pw ) {
- return true;
- }
-
-
- /**
- * Add a fulling specified mapping. Override with method to generate
- * web server specific configuration
- */
- protected boolean addMapping( String fullPath, PrintWriter pw ) {
- return true;
- }
-
- // -------------------- General Utils --------------------
-
- protected String getAbsoluteDocBase(Context context) {
- // Calculate the absolute path of the document base
- String docBase = context.getServletContext().getRealPath("/");
- docBase = docBase.substring(0,docBase.length()-1);
- if (!isAbsolute(docBase)){
- docBase = tomcatHome + "/" + docBase;
- }
- docBase = patch(docBase);
- return docBase;
- }
-
- // ------------------ Grabbed from FileUtil -----------------
- public static File getConfigFile( File base, File configDir, String defaultF )
- {
- if( base==null )
- base=new File( defaultF );
- if( ! base.isAbsolute() ) {
- if( configDir != null )
- base=new File( configDir, base.getPath());
- else
- base=new File( base.getAbsolutePath()); //??
- }
- File parent=new File(base.getParent());
- if(!parent.exists()){
- if(!parent.mkdirs()){
- throw new RuntimeException(
- "Unable to create path to config file :"+
- base.getAbsolutePath());
- }
- }
- return base;
- }
-
- public static String patch(String path) {
- String patchPath = path;
-
- // Move drive spec to the front of the path
- if (patchPath.length() >= 3 &&
- patchPath.charAt(0) == '/' &&
- Character.isLetter(patchPath.charAt(1)) &&
- patchPath.charAt(2) == ':') {
- patchPath=patchPath.substring(1,3)+"/"+patchPath.substring(3);
- }
-
- // Eliminate consecutive slashes after the drive spec
- if (patchPath.length() >= 2 &&
- Character.isLetter(patchPath.charAt(0)) &&
- patchPath.charAt(1) == ':') {
- char[] ca = patchPath.replace('/', '\\').toCharArray();
- char c;
- StringBuffer sb = new StringBuffer();
-
- for (int i = 0; i < ca.length; i++) {
- if ((ca[i] != '\\') ||
- (ca[i] == '\\' &&
- i > 0 &&
- ca[i - 1] != '\\')) {
- if (i == 0 &&
- Character.isLetter(ca[i]) &&
- i < ca.length - 1 &&
- ca[i + 1] == ':') {
- c = Character.toUpperCase(ca[i]);
- } else {
- c = ca[i];
- }
-
- sb.append(c);
- }
- }
-
- patchPath = sb.toString();
- }
-
- // fix path on NetWare - all '/' become '\\' and remove duplicate '\\'
- if (System.getProperty("os.name").startsWith("NetWare") &&
- path.length() >=3 &&
- path.indexOf(':') > 0) {
- char[] ca = patchPath.replace('/', '\\').toCharArray();
- StringBuffer sb = new StringBuffer();
-
- for (int i = 0; i < ca.length; i++) {
- if ((ca[i] != '\\') ||
- (ca[i] == '\\' && i > 0 && ca[i - 1] != '\\')) {
- sb.append(ca[i]);
- }
- }
- patchPath = sb.toString();
- }
-
- return patchPath;
- }
-
- public static boolean isAbsolute( String path ) {
- // normal file
- if( path.startsWith("/" ) ) return true;
-
- if( path.startsWith(File.separator ) ) return true;
-
- // win c:
- if (path.length() >= 3 &&
- Character.isLetter(path.charAt(0)) &&
- path.charAt(1) == ':')
- return true;
-
- // NetWare volume:
- if (System.getProperty("os.name").startsWith("NetWare") &&
- path.length() >=3 &&
- path.indexOf(':') > 0)
- return true;
-
- return false;
- }
-}
+++ /dev/null
-/*
- * 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.jk.config;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Vector;
-
-import org.w3c.dom.Node;
-
-
-/* Naming conventions:
-
-JK_CONF_DIR == serverRoot/work ( XXX /jkConfig ? )
-
-- Each vhost has a sub-dir named after the canonycal name
-
-- For each webapp in a vhost, there is a separate WEBAPP_NAME.jkmap
-
-- In httpd.conf ( or equivalent servers ), in each virtual host you
-should "Include JK_CONF_DIR/VHOST/jk_apache.conf". The config
-file will contain the Alias declarations and other rules required
-for apache operation. Same for other servers.
-
-- WebXml2Jk will be invoked by a config tool or automatically for each
-webapp - it'll generate the WEBAPP.jkmap files and config fragments.
-
-WebXml2Jk will _not_ generate anything else but mappings.
-It should _not_ try to guess locations or anything else - that's
-another components' job.
-
-*/
-
-/**
- *
- * @author Costin Manolache
- */
-public class GeneratorApache2 implements WebXml2Jk.MappingGenerator {
- WebXml2Jk wxml;
- String vhost;
- String cpath;
- String worker;
- PrintWriter out;
-
- public void setWebXmlReader(WebXml2Jk wxml ) {
- this.wxml=wxml;
- vhost=wxml.vhost;
- cpath=wxml.cpath;
- worker=wxml.worker;
- }
-
- public void generateStart() throws IOException {
- File base=wxml.getJkDir();
- File outF=new File(base, "jk2.conf");
- out=new PrintWriter( new FileWriter( outF ));
-
- out.println("# Must be included in a virtual host context for " + vhost );
-
- out.println("Alias " + cpath + " \"" + wxml.docBase + "\"");
- out.println("<Directory \"" + wxml.docBase + "\" >");
- out.println(" Options Indexes FollowSymLinks");
- generateMimeMapping( out );
- generateWelcomeFiles( out);
-
- // If we use this instead of extension mapping for jsp we can avoid most
- // jsp security problems.
- out.println(" AddHandler jakarta-servlet2 .jsp");
- out.println("</Directory>");
- out.println();
-
- out.println("<Location \"" + cpath + "/WEB-INF\" >");
- out.println(" AllowOverride None");
- out.println(" Deny from all");
- out.println("</Location>");
- out.println();
- out.println("<Location \"" + cpath + "/META-INF\" >");
- out.println(" AllowOverride None");
- out.println(" Deny from all");
- out.println("</Location>");
- out.println();
- }
-
- private void generateWelcomeFiles( PrintWriter out ) {
- Vector<String> wf= wxml.getWellcomeFiles();
- out.print(" DirectoryIndex ");
- for( int i=0; i<wf.size(); i++ ) {
- out.print( " " + wf.elementAt(i));
- }
- out.println();
- }
-
- private void generateMimeMapping( PrintWriter out ) {
- Node webN=wxml.getWebXmlNode();
- for( Node mapN=WebXml2Jk.getChild( webN, "mime-mapping" );
- mapN != null; mapN = WebXml2Jk.getNext( mapN ) ) {
- String ext=WebXml2Jk.getChildContent( mapN, "extension" );
- String type=WebXml2Jk.getChildContent( mapN, "mime-type" );
-
- out.println(" AddType " + type + " " + ext );
- }
-
-
- }
-
- public void generateEnd() {
- out.close();
- }
-
- public void generateServletMapping( String servlet, String url ) {
- out.println( "<Location \"" + cpath + url + "\" >");
- out.println( " SetHandler jakarta-servlet2" );
- out.println( " JkUriSet group " + worker );
- out.println( " JkUriSet servlet " + servlet);
- out.println( " JkUriSet host " + vhost );
- out.println( " JkUriSet context " + cpath );
- out.println( "</Location>");
- out.println();
- }
-
- public void generateFilterMapping( String servlet, String url ) {
- out.println( "<Location \"" + cpath + url + "\" >");
- out.println( " SetHandler jakarta-servlet2" );
- out.println( " JkUriSet group " + worker );
- out.println( " JkUriSet servlet " + servlet);
- out.println( " JkUriSet host " + vhost );
- out.println( " JkUriSet context " + cpath );
- out.println( "</Location>");
- out.println();
- }
-
- public void generateLoginConfig( String loginPage,
- String errPage, String authM ) {
- out.println( "<Location \"" + cpath + loginPage + "\" >");
- out.println( " SetHandler jakarta-servlet2" );
- out.println( " JkUriSet group " + worker );
- out.println( " JkUriSet host " + vhost );
- out.println( " JkUriSet context " + cpath );
- out.println( "</Location>");
- out.println();
- }
-
- public void generateErrorPage( int err, String location ) {
-
- }
-
- // XXX Only if BASIC/DIGEST and 'integrated auth'
- public void generateConstraints( Vector<String> urls, Vector<String> methods,
- Vector<String> roles, boolean isSSL ) {
- for( int i=0; i<urls.size(); i++ ) {
- String url = urls.elementAt(i);
-
- out.println( "<Location \"" + cpath + url + "\" >");
-
- if( methods.size() > 0 ) {
- out.print(" <Limit ");
- for( int j=0; j<methods.size(); j++ ) {
- String m = methods.elementAt(j);
- out.print( " " + m);
- }
- out.println( " >" );
- }
-
- out.println( " AuthType basic" );
- out.print( " Require group " );
- for( int j=0; j<roles.size(); j++ ) {
- String role = roles.elementAt(j);
- out.print( " " + role);
- }
- out.println();
-
- if( methods.size() > 0 ) {
- out.println(" </Limit>");
- }
-
- out.println( "</Location>");
- }
- }
-}
+++ /dev/null
-/*
- * 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.jk.config;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Vector;
-
-
-/* Naming conventions:
-
-JK_CONF_DIR == serverRoot/work ( XXX /jkConfig ? )
-
-- Each vhost has a sub-dir named after the canonycal name
-
-- For each webapp in a vhost, there is a separate WEBAPP_NAME.jkmap
-
-- In httpd.conf ( or equivalent servers ), in each virtual host you
-should "Include JK_CONF_DIR/VHOST/jk_apache.conf". The config
-file will contain the Alias declarations and other rules required
-for apache operation. Same for other servers.
-
-- WebXml2Jk will be invoked by a config tool or automatically for each
-webapp - it'll generate the WEBAPP.jkmap files and config fragments.
-
-WebXml2Jk will _not_ generate anything else but mappings.
-It should _not_ try to guess locations or anything else - that's
-another components' job.
-
-*/
-
-/**
- *
- * @author Costin Manolache
- */
-public class GeneratorJk1 implements WebXml2Jk.MappingGenerator {
- WebXml2Jk wxml;
- String vhost;
- String cpath;
- String worker;
- PrintWriter out;
-
- public void setWebXmlReader(WebXml2Jk wxml ) {
- this.wxml=wxml;
- vhost=wxml.vhost;
- cpath=wxml.cpath;
- worker=wxml.worker;
- }
-
- public void generateStart( ) throws IOException {
- File base=wxml.getJkDir();
- File outF=new File(base, "jk.conf");
- out=new PrintWriter( new FileWriter( outF ));
-
- out.println("# This must be included in the virtual host section for " + vhost );
- }
-
- public void generateEnd() {
- out.close();
- }
-
-
- public void generateServletMapping( String servlet, String url ) {
- out.println( "JkMount " + cpath + url + " " + worker);
- }
-
- public void generateFilterMapping( String servlet, String url ) {
- out.println( "JkMount " + cpath + url + " " + worker);
- }
-
- public void generateLoginConfig( String loginPage,
- String errPage, String authM ) {
- out.println( "JkMount " + cpath + loginPage + " " + worker);
- }
-
- public void generateErrorPage( int err, String location ) {
-
- }
-
- public void generateMimeMapping( String ext, String type ) {
-
- }
-
- public void generateWelcomeFiles( Vector<String> wf ) {
-
- }
-
-
- public void generateConstraints( Vector<String> urls, Vector<String> methods,
- Vector<String> roles, boolean isSSL ) {
- for( int i=0; i<urls.size(); i++ ) {
- String url = urls.elementAt(i);
-
- out.println( "JkMount " + cpath + url + " " + worker);
- }
- }
-}
+++ /dev/null
-/*
- * 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.jk.config;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Vector;
-
-
-/* Naming conventions:
-
-JK_CONF_DIR == serverRoot/work ( XXX /jkConfig ? )
-
-- Each vhost has a sub-dir named after the canonycal name
-
-- For each webapp in a vhost, there is a separate WEBAPP_NAME.jkmap
-
-- In httpd.conf ( or equivalent servers ), in each virtual host you
-should "Include JK_CONF_DIR/VHOST/jk_apache.conf". The config
-file will contain the Alias declarations and other rules required
-for apache operation. Same for other servers.
-
-- WebXml2Jk will be invoked by a config tool or automatically for each
-webapp - it'll generate the WEBAPP.jkmap files and config fragments.
-
-WebXml2Jk will _not_ generate anything else but mappings.
-It should _not_ try to guess locations or anything else - that's
-another components' job.
-
-*/
-
-/**
- *
- * @author Costin Manolache
- */
-public class GeneratorJk2 implements WebXml2Jk.MappingGenerator {
- WebXml2Jk wxml;
- String vhost;
- String cpath;
- String worker;
- PrintWriter out;
-
- public void setWebXmlReader(WebXml2Jk wxml ) {
- this.wxml=wxml;
- vhost=wxml.vhost;
- cpath=wxml.cpath;
- worker=wxml.worker;
- }
-
- public void generateStart( ) throws IOException {
- File base=wxml.getJkDir();
- File outF=new File(base, "jk2map.properties");
- out=new PrintWriter( new FileWriter( outF ));
-
- out.println("# Autogenerated from web.xml" );
- }
-
- public void generateEnd() {
- out.close();
- }
-
- public void generateServletMapping( String servlet, String url ) {
- out.println( "[uri:" + vhost + cpath + url + "]");
- out.println( "group=" + worker );
- out.println( "servlet=" + servlet);
- out.println( "host=" + vhost);
- out.println( "context=" + cpath);
- out.println();
- }
-
- public void generateFilterMapping( String servlet, String url ) {
- out.println( "[url:" + vhost + cpath + url + "]");
- out.println( "group=" + worker );
- out.println( "filter=" + servlet);
- out.println( "host=" + vhost);
- out.println( "context=" + cpath);
- out.println();
- }
-
- public void generateLoginConfig( String loginPage,
- String errPage, String authM ) {
- out.println("[url:" + vhost + cpath + loginPage + "]" );
- out.println( "group=" + worker );
- out.println( "host=" + vhost);
- out.println( "context=" + cpath);
- out.println();
- out.println("[url:" + vhost + cpath + errPage + "]" );
- out.println( "group=" + worker );
- out.println( "host=" + vhost);
- out.println( "context=" + cpath);
- out.println();
- }
-
- public void generateErrorPage( int err, String location ) {
-
- }
-
- public void generateMimeMapping( String ext, String type ) {
-
- }
-
- public void generateWelcomeFiles( Vector<String> wf ) {
-
- }
-
-
- public void generateConstraints(Vector<String> urls, Vector<String> methods,
- Vector<String> roles, boolean isSSL ) {
- for( int i=0; i<urls.size(); i++ ) {
- String url=urls.elementAt(i);
-
- out.println("[url:" + vhost + cpath + url + "]");
- out.println( "group=" + worker );
- out.println( "host=" + vhost);
- out.println( "context=" + cpath);
- for( int j=0; j<roles.size(); j++ ) {
- String role=roles.elementAt(j);
- out.println( "role=" + role);
- }
- for( int j=0; j<methods.size(); j++ ) {
- String m=methods.elementAt(j);
- out.println( "method=" + m);
- }
- if( isSSL )
- out.println("ssl=true");
- }
- }
-}
+++ /dev/null
-/*
- * 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.jk.config;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Date;
-
-import org.apache.catalina.Context;
-
-
-/**
- Generates automatic IIS isapi_redirect configurations based on
- the Tomcat server.xml settings and the war contexts
- initialized during startup.
- <p>
- This config interceptor is enabled by inserting an IISConfig
- element in the <b><ContextManager></b> tag body inside
- the server.xml file like so:
- <pre>
- * < ContextManager ... >
- * ...
- * <<b>IISConfig</b> <i>options</i> />
- * ...
- * < /ContextManager >
- </pre>
- where <i>options</i> can include any of the following attributes:
- <ul>
- <li><b>configHome</b> - default parent directory for the following paths.
- If not set, this defaults to TOMCAT_HOME. Ignored
- whenever any of the following paths is absolute.
- </li>
- <li><b>regConfig</b> - path to use for writing IIS isapi_redirect registry
- file. If not set, defaults to
- "conf/auto/iis_redirect.reg".</li>
- <li><b>workersConfig</b> - path to workers.properties file used by
- isapi_redirect. If not set, defaults to
- "conf/jk/workers.properties".</li>
- <li><b>uriConfig</b> - path to use for writing IIS isapi_redirect uriworkermap
- file. If not set, defaults to
- "conf/auto/uriworkermap.properties".</li>
- <li><b>jkLog</b> - path to log file to be used by isapi_redirect.</li>
- <li><b>jkDebug</b> - Loglevel setting. May be debug, info, error, or emerg.
- If not set, defaults to emerg.</li>
- <li><b>jkWorker</b> The desired worker. Must be set to one of the workers
- defined in the workers.properties file. "ajp12", "ajp13"
- or "inprocess" are the workers found in the default
- workers.properties file. If not specified, defaults
- to "ajp13" if an Ajp13Interceptor is in use, otherwise
- it defaults to "ajp12".</li>
- <li><b>forwardAll</b> - If true, forward all requests to Tomcat. This helps
- insure that all the behavior configured in the web.xml
- file functions correctly. If false, let IIS serve
- static resources assuming it has been configured
- to do so. The default is true.
- Warning: When false, some configuration in
- the web.xml may not be duplicated in IIS.
- Review the uriworkermap file to see what
- configuration is actually being set in IIS.</li>
- <li><b>noRoot</b> - If true, the root context is not mapped to
- Tomcat. If false and forwardAll is true, all requests
- to the root context are mapped to Tomcat. If false and
- forwardAll is false, only JSP and servlets requests to
- the root context are mapped to Tomcat. When false,
- to correctly serve Tomcat's root context you must also
- modify the Home Directory setting in IIS
- to point to Tomcat's root context directory.
- Otherwise some content, such as the root index.html,
- will be served by IIS before isapi_redirect gets a chance
- to claim the request and pass it to Tomcat.
- The default is true.</li>
- </ul>
- <p>
- @author Costin Manolache
- @author Larry Isaacs
- @author Gal Shachor
- @author Bill Barker
- */
-public class IISConfig extends BaseJkConfig {
- private static org.apache.juli.logging.Log log =
- org.apache.juli.logging.LogFactory.getLog(IISConfig.class);
-
- public static final String WORKERS_CONFIG = "/conf/jk/workers.properties";
- public static final String URI_WORKERS_MAP_CONFIG = "/conf/auto/uriworkermap.properties";
- public static final String ISAPI_LOG_LOCATION = "/logs/iis_redirect.log";
- public static final String ISAPI_REG_FILE = "/conf/auto/iis_redirect.reg";
-
- private File regConfig = null;
- private File uriConfig = null;
-
- public IISConfig()
- {
- }
-
- //-------------------- Properties --------------------
-
- /**
- set the path to the output file for the auto-generated
- isapi_redirect registry file. If this path is relative
- then getRegConfig() will resolve it absolutely against
- the getConfigHome() path.
- <p>
- @param path String path to a file
- */
- public void setRegConfig(String path){
- regConfig= (path==null)?null:new File(path);
- }
-
- /**
- set a path to the uriworkermap.properties file.
- @param path String path to uriworkermap.properties file
- */
- public void setUriConfig(String path){
- uriConfig= (path==null?null:new File(path));
- }
-
- // -------------------- Initialize/guess defaults --------------------
-
- /** Initialize defaults for properties that are not set
- explicitely
- */
- protected void initProperties() {
- super.initProperties();
-
- regConfig=getConfigFile( regConfig, configHome, ISAPI_REG_FILE);
- workersConfig=getConfigFile( workersConfig, configHome, WORKERS_CONFIG);
- uriConfig=getConfigFile( uriConfig, configHome, URI_WORKERS_MAP_CONFIG);
- jkLog=getConfigFile( jkLog, configHome, ISAPI_LOG_LOCATION);
- }
-
- // -------------------- Generate config --------------------
-
- protected PrintWriter getWriter() throws IOException {
- String abUriConfig = uriConfig.getAbsolutePath();
- return new PrintWriter(new FileWriter(abUriConfig,append));
- }
- protected boolean generateJkHead(PrintWriter mod_jk) {
- try {
- PrintWriter regfile = new PrintWriter(new FileWriter(regConfig));
- log.info("Generating IIS registry file = "+regConfig );
- generateRegistrySettings(regfile);
- regfile.close();
- } catch(IOException iex) {
- log.warn("Unable to generate registry file " +regConfig);
- return false;
- }
- log.info("Generating IIS URI worker map file = "+uriConfig );
- generateUriWorkerHeader(mod_jk);
- return true;
- }
-
- // -------------------- Config sections --------------------
-
- /** Writes the registry settings required by the IIS connector
- */
- private void generateRegistrySettings(PrintWriter regfile)
- {
- regfile.println("REGEDIT4");
- regfile.println();
- regfile.println("[HKEY_LOCAL_MACHINE\\SOFTWARE\\Apache Software Foundation\\Jakarta Isapi Redirector\\1.0]");
- regfile.println("\"extension_uri\"=\"/jakarta/isapi_redirect.dll\"");
- regfile.println("\"log_file\"=\"" + dubleSlash(jkLog.toString()) +"\"");
- regfile.println("\"log_level\"=\"" + jkDebug + "\"");
- regfile.println("\"worker_file\"=\"" + dubleSlash(workersConfig.toString()) +"\"");
- regfile.println("\"worker_mount_file\"=\"" + dubleSlash(uriConfig.toString()) +"\"");
- }
-
- /** Writes the header information to the uriworkermap file
- */
- private void generateUriWorkerHeader(PrintWriter uri_worker)
- {
- uri_worker.println("###################################################################");
- uri_worker.println("# Auto generated configuration. Dated: " + new Date());
- uri_worker.println("###################################################################");
- uri_worker.println();
-
- uri_worker.println("#");
- uri_worker.println("# Default worker to be used through our mappings");
- uri_worker.println("#");
- uri_worker.println("default.worker=" + jkWorker);
- uri_worker.println();
- }
-
- /** Forward all requests for a context to tomcat.
- The default.
- */
- protected void generateStupidMappings(Context context, PrintWriter uri_worker )
- {
- String ctxPath = context.getPath();
- String nPath=("".equals(ctxPath)) ? "/" : ctxPath;
-
- if( noRoot && "".equals(ctxPath) ) {
- log.debug("Ignoring root context in forward-all mode ");
- return;
- }
-
- // map all requests for this context to Tomcat
- uri_worker.println(nPath +"=$(default.worker)");
- if( "".equals(ctxPath) ) {
- uri_worker.println(nPath +"*=$(default.worker)");
- uri_worker.println(
- "# Note: To correctly serve the Tomcat's root context, IIS's Home Directory must");
- uri_worker.println(
- "# must be set to: \"" + getAbsoluteDocBase(context) + "\"");
- }
- else
- uri_worker.println(nPath +"/*=$(default.worker)");
- }
-
- protected void generateContextMappings(Context context, PrintWriter uri_worker )
- {
- String ctxPath = context.getPath();
- String nPath=("".equals(ctxPath)) ? "/" : ctxPath;
-
- if( noRoot && "".equals(ctxPath) ) {
- log.debug("Ignoring root context in forward-all mode ");
- return;
- }
-
- // Static files will be served by IIS
- uri_worker.println();
- uri_worker.println("#########################################################");
- uri_worker.println("# Auto configuration for the " + nPath + " context.");
- uri_worker.println("#########################################################");
- uri_worker.println();
-
- // Static mappings are not set in uriworkermap, but must be set with IIS admin.
-
- // InvokerInterceptor - it doesn't have a container,
- // but it's implemented using a special module.
-
- // XXX we need to better collect all mappings
-
- if(context.getLoginConfig() != null) {
- String loginPage = context.getLoginConfig().getLoginPage();
- if(loginPage != null) {
- int lpos = loginPage.lastIndexOf("/");
- String jscurl = loginPage.substring(0,lpos+1) + "j_security_check";
- addMapping( ctxPath, jscurl, uri_worker);
- }
- }
- String [] servletMaps=context.findServletMappings();
- for( int ii=0; ii < servletMaps.length ; ii++) {
- addMapping( ctxPath , servletMaps[ii] , uri_worker );
- }
- }
-
- /** Add an IIS extension mapping.
- */
- protected boolean addMapping( String ctxPath, String ext,
- PrintWriter uri_worker )
- {
- if( log.isDebugEnabled() )
- log.debug( "Adding extension map for " + ctxPath + "/*." + ext );
- if(! ext.startsWith("/") )
- ext = "/" + ext;
- if(ext.length() > 1)
- uri_worker.println(ctxPath + "/*." + ext + "=$(default.worker)");
- return true;
- }
-
- /** Add a fulling specified IIS mapping.
- */
- protected boolean addMapping( String fullPath, PrintWriter uri_worker ) {
- if( log.isDebugEnabled() )
- log.debug( "Adding map for " + fullPath );
- uri_worker.println(fullPath + "=$(default.worker)" );
- return true;
- }
-
- // -------------------- Utils --------------------
-
- private String dubleSlash(String in)
- {
- StringBuffer sb = new StringBuffer();
-
- for(int i = 0 ; i < in.length() ; i++) {
- char ch = in.charAt(i);
- if('\\' == ch) {
- sb.append("\\\\");
- } else {
- sb.append(ch);
- }
- }
-
- return sb.toString();
- }
-
-}
+++ /dev/null
-/*
- * 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.jk.config;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Date;
-
-import org.apache.catalina.Context;
-
-
-/**
- Generates automatic Netscape nsapi_redirect configurations based on
- the Tomcat server.xml settings and the war contexts
- initialized during startup.
- <p>
- This config interceptor is enabled by inserting an NSConfig
- element in the <b><ContextManager></b> tag body inside
- the server.xml file like so:
- <pre>
- * < ContextManager ... >
- * ...
- * <<b>NSConfig</b> <i>options</i> />
- * ...
- * < /ContextManager >
- </pre>
- where <i>options</i> can include any of the following attributes:
- <ul>
- <li><b>configHome</b> - default parent directory for the following paths.
- If not set, this defaults to TOMCAT_HOME. Ignored
- whenever any of the following paths is absolute.
- </li>
- <li><b>objConfig</b> - path to use for writing Netscape obj.conf
- file. If not set, defaults to
- "conf/auto/obj.conf".</li>
- <li><b>objectName</b> - Name of the Object to execute the requests.
- Defaults to "servlet".</li>
- <li><b>workersConfig</b> - path to workers.properties file used by
- nsapi_redirect. If not set, defaults to
- "conf/jk/workers.properties".</li>
- <li><b>nsapiJk</b> - path to Netscape mod_jk plugin file. If not set,
- defaults to "bin/nsapi_redirect.dll" on windows,
- "bin/nsapi_rd.nlm" on netware, and
- "bin/nsapi_redirector.so" everywhere else.</li>
- <li><b>jkLog</b> - path to log file to be used by nsapi_redirect.</li>
- <li><b>jkDebug</b> - Loglevel setting. May be debug, info, error, or emerg.
- If not set, defaults to emerg.</li>
- <li><b>jkWorker</b> The desired worker. Must be set to one of the workers
- defined in the workers.properties file. "ajp12", "ajp13"
- or "inprocess" are the workers found in the default
- workers.properties file. If not specified, defaults
- to "ajp13" if an Ajp13Interceptor is in use, otherwise
- it defaults to "ajp12".</li>
- <li><b>forwardAll</b> - If true, forward all requests to Tomcat. This helps
- insure that all the behavior configured in the web.xml
- file functions correctly. If false, let Netscape serve
- static resources assuming it has been configured
- to do so. The default is true.
- Warning: When false, some configuration in
- the web.xml may not be duplicated in Netscape.
- Review the uriworkermap file to see what
- configuration is actually being set in Netscape.</li>
- <li><b>noRoot</b> - If true, the root context is not mapped to
- Tomcat. If false and forwardAll is true, all requests
- to the root context are mapped to Tomcat. If false and
- forwardAll is false, only JSP and servlets requests to
- the root context are mapped to Tomcat. When false,
- to correctly serve Tomcat's root context you must also
- modify the Home Directory setting in Netscape
- to point to Tomcat's root context directory.
- Otherwise some content, such as the root index.html,
- will be served by Netscape before nsapi_redirect gets a chance
- to claim the request and pass it to Tomcat.
- The default is true.</li>
- </ul>
- <p>
- @author Costin Manolache
- @author Larry Isaacs
- @author Gal Shachor
- @author Bill Barker
- */
-public class NSConfig extends BaseJkConfig {
- private static org.apache.juli.logging.Log log =
- org.apache.juli.logging.LogFactory.getLog(NSConfig.class);
-
- public static final String WORKERS_CONFIG = "/conf/jk/workers.properties";
- public static final String NS_CONFIG = "/conf/auto/obj.conf";
- public static final String NSAPI_LOG_LOCATION = "/logs/nsapi_redirect.log";
- /** default location of nsapi plug-in. */
- public static final String NSAPI_REDIRECTOR;
-
- //set up some defaults based on OS type
- static{
- String os = System.getProperty("os.name").toLowerCase();
- if(os.indexOf("windows")>=0){
- NSAPI_REDIRECTOR = "bin/nsapi_redirect.dll";
- }else if(os.indexOf("netware")>=0){
- NSAPI_REDIRECTOR = "bin/nsapi_rd.nlm";
- }else{
- NSAPI_REDIRECTOR = "bin/nsapi_redirector.so";
- }
- }
-
- private File objConfig = null;
- private File nsapiJk = null;
- private String objectName = "servlet";
-
- public NSConfig()
- {
- }
-
- //-------------------- Properties --------------------
-
- /**
- set the path to the output file for the auto-generated
- isapi_redirect registry file. If this path is relative
- then getRegConfig() will resolve it absolutely against
- the getConfigHome() path.
- <p>
- @param path String path to a file
- */
- public void setObjConfig(String path) {
- objConfig= (path==null)?null:new File(path);
- }
-
- /**
- set the path to the nsapi plugin module
- @param path String path to a file
- */
- public void setNsapiJk(String path) {
- nsapiJk=( path==null?null:new File(path));
- }
-
- /**
- Set the name for the Object that implements the
- jk_service call.
- @param name Name of the obj.conf Object
- */
- public void setObjectName(String name) {
- objectName = name;
- }
-
- // -------------------- Initialize/guess defaults --------------------
-
- /** Initialize defaults for properties that are not set
- explicitely
- */
- protected void initProperties() {
- super.initProperties();
-
- objConfig=getConfigFile( objConfig, configHome, NS_CONFIG);
- workersConfig=getConfigFile( workersConfig, configHome, WORKERS_CONFIG);
-
- if( nsapiJk == null )
- nsapiJk=new File(NSAPI_REDIRECTOR);
- else
- nsapiJk =getConfigFile( nsapiJk, configHome, NSAPI_REDIRECTOR );
- jkLog=getConfigFile( jkLog, configHome, NSAPI_LOG_LOCATION);
- }
-
- // -------------------- Generate config --------------------
- protected PrintWriter getWriter() throws IOException {
- String abObjConfig = objConfig.getAbsolutePath();
- return new PrintWriter(new FileWriter(abObjConfig,append));
- }
- protected boolean generateJkHead(PrintWriter mod_jk) {
- log.info("Generating netscape web server config = "+objConfig );
-
- generateNsapiHead( mod_jk );
-
- mod_jk.println("<Object name=default>");
- return true;
- }
-
- private void generateNsapiHead(PrintWriter objfile)
- {
- objfile.println("###################################################################");
- objfile.println("# Auto generated configuration. Dated: " + new Date());
- objfile.println("###################################################################");
- objfile.println();
-
- objfile.println("#");
- objfile.println("# You will need to merge the content of this file with your ");
- objfile.println("# regular obj.conf and then restart (=stop + start) your Netscape server. ");
- objfile.println("#");
- objfile.println();
-
- objfile.println("#");
- objfile.println("# Loading the redirector into your server");
- objfile.println("#");
- objfile.println();
- objfile.println("Init fn=\"load-modules\" funcs=\"jk_init,jk_service\" shlib=\"<put full path to the redirector here>\"");
- objfile.println("Init fn=\"jk_init\" worker_file=\"" +
- workersConfig.toString().replace('\\', '/') +
- "\" log_level=\"" + jkDebug + "\" log_file=\"" +
- jkLog.toString().replace('\\', '/') +
- "\"");
- objfile.println();
- }
-
- protected void generateJkTail(PrintWriter objfile)
- {
- objfile.println();
- objfile.println("#######################################################");
- objfile.println("# Protecting the WEB-INF and META-INF directories.");
- objfile.println("#######################################################");
- objfile.println("PathCheck fn=\"deny-existence\" path=\"*/WEB-INF/*\"");
- objfile.println("PathCheck fn=\"deny-existence\" path=\"*/META-INF/*\"");
- objfile.println();
-
- objfile.println("</Object>");
- objfile.println();
-
- objfile.println("#######################################################");
- objfile.println("# New object to execute your servlet requests.");
- objfile.println("#######################################################");
- objfile.println("<Object name=" + objectName + ">");
- objfile.println("ObjectType fn=force-type type=text/html");
- objfile.println("Service fn=\"jk_service\" worker=\""+ jkWorker + "\" path=\"/*\"");
- objfile.println("</Object>");
- objfile.println();
- }
-
- // -------------------- Forward all mode --------------------
-
- /** Forward all requests for a context to tomcat.
- The default.
- */
- protected void generateStupidMappings(Context context, PrintWriter objfile )
- {
- String ctxPath = context.getPath();
-
- if( noRoot && "".equals(ctxPath) ) {
- log.debug("Ignoring root context in forward-all mode ");
- return;
- }
- objfile.println("<Object name=" + context.getName() + ">");
-
- objfile.println("NameTrans fn=\"assign-name\" from=\"" + ctxPath + "\" name=\"" + objectName + "\"");
- objfile.println("NameTrans fn=\"assign-name\" from=\"" + ctxPath + "/*\" name=\"" + objectName + "\"");
- objfile.println("</Object>");
- }
-
-
- // -------------------- Netscape serves static mode --------------------
- // This is not going to work for all apps. We fall back to stupid mode.
-
- protected void generateContextMappings(Context context, PrintWriter objfile )
- {
- String ctxPath = context.getPath();
- String nPath=("".equals(ctxPath)) ? "/" : ctxPath;
-
- if( noRoot && "".equals(ctxPath) ) {
- log.debug("Ignoring root context in non-forward-all mode ");
- return;
- }
- objfile.println("<Object name=" + context.getName() + ">");
- // Static files will be served by Netscape
- objfile.println("#########################################################");
- objfile.println("# Auto configuration for the " + nPath + " context starts.");
- objfile.println("#########################################################");
- objfile.println();
-
- // XXX Need to determine what if/how static mappings are done
-
- // InvokerInterceptor - it doesn't have a container,
- // but it's implemented using a special module.
-
- // XXX we need to better collect all mappings
- if(context.getLoginConfig() != null) {
- String loginPage = context.getLoginConfig().getLoginPage();
- if(loginPage != null) {
- int lpos = loginPage.lastIndexOf("/");
- String jscurl = loginPage.substring(0,lpos+1) + "j_security_check";
- addMapping( ctxPath, jscurl, objfile);
- }
- }
-
- String [] servletMaps=context.findServletMappings();
- for(int ii=0; ii < servletMaps.length; ii++) {
- addMapping( ctxPath , servletMaps[ii] , objfile );
- }
- objfile.println("</Object>");
- }
-
- /** Add a Netscape extension mapping.
- */
- protected boolean addMapping( String ctxPath, String ext,
- PrintWriter objfile )
- {
- if( log.isDebugEnabled() )
- log.debug( "Adding extension map for " + ctxPath + "/*." + ext );
- if(! ext.startsWith("/") )
- ext = "/" + ext;
- if(ext.length() > 1)
- objfile.println("NameTrans fn=\"assign-name\" from=\"" +
- ctxPath + ext + "\" name=\"" + objectName + "\"");
- return true;
- }
-
- /** Add a fulling specified Netscape mapping.
- */
- protected boolean addMapping( String fullPath, PrintWriter objfile ) {
- if( log.isDebugEnabled() )
- log.debug( "Adding map for " + fullPath );
- objfile.println("NameTrans fn=\"assign-name\" from=\"" +
- fullPath + "\" name=\"" + objectName + "\"");
- return true;
- }
-
-}
+++ /dev/null
-/*
- * 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.jk.config;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.Hashtable;
-import java.util.Vector;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.apache.tomcat.util.IntrospectionUtils;
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.xml.sax.EntityResolver;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
-
-/* Naming conventions:
-
-JK_CONF_DIR == serverRoot/work ( XXX /jkConfig ? )
-
-- Each vhost has a sub-dir named after the canonycal name
-
-- For each webapp in a vhost, there is a separate WEBAPP_NAME.jkmap
-
-- In httpd.conf ( or equivalent servers ), in each virtual host you
-should "Include JK_CONF_DIR/VHOST/jk_apache.conf". The config
-file will contain the Alias declarations and other rules required
-for apache operation. Same for other servers.
-
-- WebXml2Jk will be invoked by a config tool or automatically for each
-webapp - it'll generate the WEBAPP.jkmap files and config fragments.
-
-WebXml2Jk will _not_ generate anything else but mappings.
-It should _not_ try to guess locations or anything else - that's
-another components' job.
-
-*/
-
-/**
- * Read a web.xml file and generate the mappings for jk2.
- * It can be used from the command line or ant.
- *
- * In order for the web server to serve static pages, all webapps
- * must be deployed on the computer that runs Apache, IIS, etc.
- *
- * Dynamic pages can be executed on that computer or other servers
- * in a pool, but even if the main server doesn't run tomcat,
- * it must have all the static files and WEB-INF/web.xml.
- * ( you could have a script remove everything else, including jsps - if
- * security paranoia is present ).
- *
- * XXX We could have this in WEB-INF/urimap.properties.
- *
- * @author Costin Manolache
- */
-public class WebXml2Jk {
- String vhost="";
- String cpath="";
- String docBase;
- String file;
- String worker="lb";
-
- // -------------------- Settings --------------------
-
- // XXX We can also generate location-independent mappings.
-
- /** Set the canonycal name of the virtual host.
- */
- public void setHost( String vhost ) {
- this.vhost=vhost;
- }
-
- /** Set the canonical name of the virtual host.
- */
- public void setContext( String contextPath ) {
- this.cpath=contextPath;
- }
-
-
- /** Set the base directory where the application is
- * deployed ( on the web server ).
- */
- public void setDocBase(String docBase ) {
- this.docBase=docBase;
- }
-
- // Automatically generated.
-// /** The file where the jk2 mapping will be generated
-// */
-// public void setJk2Conf( String outFile ) {
-// file=outFile;
-// type=CONFIG_JK2_URIMAP;
-// }
-
-// /** Backward compat: generate JkMounts for mod_jk1
-// */
-// public void setJkmountFile( String outFile ) {
-// file=outFile;
-// type=CONFIG_JK_MOUNT;
-// }
-
- /* By default we map to the lb - in jk2 this is automatically
- * created and includes all tomcat instances.
- *
- * This is equivalent to the worker in jk1.
- */
- public void setGroup(String route ) {
- worker=route;
- }
-
- // -------------------- Generators --------------------
- public static interface MappingGenerator {
- void setWebXmlReader(WebXml2Jk wxml );
-
- /** Start section( vhost declarations, etc )
- */
- void generateStart() throws IOException ;
-
- void generateEnd() throws IOException ;
-
- void generateServletMapping( String servlet, String url )throws IOException ;
- void generateFilterMapping( String servlet, String url ) throws IOException ;
-
- void generateLoginConfig( String loginPage,
- String errPage, String authM ) throws IOException ;
-
- void generateErrorPage( int err, String location ) throws IOException ;
-
- void generateConstraints( Vector<String> urls, Vector<String> methods,
- Vector<String> roles, boolean isSSL ) throws IOException ;
- }
-
- // -------------------- Implementation --------------------
- Node webN;
- File jkDir;
-
- /** Return the top level node
- */
- public Node getWebXmlNode() {
- return webN;
- }
-
- public File getJkDir() {
- return jkDir;
- }
-
- /** Extract the welcome files from the web.xml
- */
- public Vector<String> getWellcomeFiles() {
- Node n0=getChild( webN, "welcome-file-list" );
- Vector<String> wF = new Vector<String>();
- if( n0!=null ) {
- for( Node mapN=getChild( webN, "welcome-file" );
- mapN != null; mapN = getNext( mapN ) ) {
- wF.addElement( getContent(mapN));
- }
- }
- // XXX Add index.html, index.jsp
- return wF;
- }
-
-
- void generate(MappingGenerator gen ) throws IOException {
- gen.generateStart();
- log.info("Generating mappings for servlets " );
- for( Node mapN=getChild( webN, "servlet-mapping" );
- mapN != null; mapN = getNext( mapN ) ) {
-
- String serv=getChildContent( mapN, "servlet-name");
- String url=getChildContent( mapN, "url-pattern");
-
- gen.generateServletMapping( serv, url );
- }
-
- log.info("Generating mappings for filters " );
- for( Node mapN=getChild( webN, "filter-mapping" );
- mapN != null; mapN = getNext( mapN ) ) {
-
- String filter=getChildContent( mapN, "filter-name");
- String url=getChildContent( mapN, "url-pattern");
-
- gen.generateFilterMapping( filter, url );
- }
-
-
- for( Node mapN=getChild( webN, "error-page" );
- mapN != null; mapN = getNext( mapN ) ) {
- String errorCode= getChildContent( mapN, "error-code" );
- String location= getChildContent( mapN, "location" );
-
- if( errorCode!=null && ! "".equals( errorCode ) ) {
- try {
- int err=new Integer( errorCode ).intValue();
- gen.generateErrorPage( err, location );
- } catch( Exception ex ) {
- log.error( "Format error " + location, ex);
- }
- }
- }
-
- Node lcN=getChild( webN, "login-config" );
- if( lcN!=null ) {
- log.info("Generating mapping for login-config " );
-
- String authMeth=getContent( getChild( lcN, "auth-method"));
- if( authMeth == null ) authMeth="BASIC";
-
- Node n1=getChild( lcN, "form-login-config");
- String loginPage= getChildContent( n1, "form-login-page");
- String errPage= getChildContent( n1, "form-error-page");
-
- if(loginPage != null) {
- int lpos = loginPage.lastIndexOf("/");
- String jscurl = loginPage.substring(0,lpos+1) + "j_security_check";
- gen.generateLoginConfig( jscurl, errPage, authMeth );
- }
- }
-
- log.info("Generating mappings for security constraints " );
- for( Node mapN=getChild( webN, "security-constraint" );
- mapN != null; mapN = getNext( mapN )) {
-
- Vector<String> methods = new Vector<String>();
- Vector<String> urls= new Vector<String>();
- Vector<String> roles= new Vector<String>();
- boolean isSSL=false;
-
- Node wrcN=getChild( mapN, "web-resource-collection");
- for( Node uN=getChild(wrcN, "http-method");
- uN!=null; uN=getNext( uN )) {
- methods.addElement( getContent( uN ));
- }
- for( Node uN=getChild(wrcN, "url-pattern");
- uN!=null; uN=getNext( uN )) {
- urls.addElement( getContent( uN ));
- }
-
- // Not used at the moment
- Node acN=getChild( mapN, "auth-constraint");
- for( Node rN=getChild(acN, "role-name");
- rN!=null; rN=getNext( rN )) {
- roles.addElement(getContent( rN ));
- }
-
- Node ucN=getChild( mapN, "user-data-constraint");
- String transp=getContent(getChild( ucN, "transport-guarantee"));
- if( transp!=null ) {
- if( "INTEGRAL".equalsIgnoreCase( transp ) ||
- "CONFIDENTIAL".equalsIgnoreCase( transp ) ) {
- isSSL=true;
- }
- }
-
- gen.generateConstraints( urls, methods, roles, isSSL );
- }
- gen.generateEnd();
- }
-
- // -------------------- Main and ant wrapper --------------------
-
- public void execute() {
- try {
- if( docBase== null) {
- log.error("No docbase - please specify the base directory of you web application ( -docBase PATH )");
- return;
- }
- if( cpath== null) {
- log.error("No context - please specify the mount ( -context PATH )");
- return;
- }
- File docbF=new File(docBase);
- File wXmlF=new File( docBase, "WEB-INF/web.xml");
-
- Document wXmlN=readXml(wXmlF);
- if( wXmlN == null ) return;
-
- webN = wXmlN.getDocumentElement();
- if( webN==null ) {
- log.error("Can't find web-app");
- return;
- }
-
- jkDir=new File( docbF, "WEB-INF/jk2" );
- jkDir.mkdirs();
-
- MappingGenerator generator=new GeneratorJk2();
- generator.setWebXmlReader( this );
- generate( generator );
-
- generator=new GeneratorJk1();
- generator.setWebXmlReader( this );
- generate( generator );
-
- generator=new GeneratorApache2();
- generator.setWebXmlReader( this );
- generate( generator );
-
- } catch( Exception ex ) {
- ex.printStackTrace();
- }
- }
-
-
- public static void main(String args[] ) {
- try {
- if( args.length == 1 &&
- ( "-?".equals(args[0]) || "-h".equals( args[0])) ) {
- System.out.println("Usage: ");
- System.out.println(" WebXml2Jk [OPTIONS]");
- System.out.println();
- System.out.println(" -docBase DIR The location of the webapp. Required");
- System.out.println(" -group GROUP Group, if you have multiple tomcats with diffrent content. " );
- System.out.println(" The default is 'lb', and should be used in most cases");
- System.out.println(" -host HOSTNAME Canonical hostname - for virtual hosts");
- System.out.println(" -context /CPATH Context path where the app will be mounted");
- return;
- }
-
- WebXml2Jk w2jk=new WebXml2Jk();
-
- /* do ant-style property setting */
- IntrospectionUtils.processArgs( w2jk, args, new String[] {},
- null, new Hashtable<Object, Object>());
- w2jk.execute();
- } catch( Exception ex ) {
- ex.printStackTrace();
- }
-
- }
-
- private static org.apache.juli.logging.Log log=
- org.apache.juli.logging.LogFactory.getLog( WebXml2Jk.class );
-
-
- // -------------------- DOM utils --------------------
-
- /** Get the content of a node
- */
- public static String getContent(Node n ) {
- if( n==null ) return null;
- Node n1=n.getFirstChild();
- // XXX Check if it's a text node
-
- String s1=n1.getNodeValue();
- return s1.trim();
- }
-
- /** Get the first child
- */
- public static Node getChild( Node parent, String name ) {
- if( parent==null ) return null;
- Node first=parent.getFirstChild();
- if( first==null ) return null;
- for (Node node = first; node != null;
- node = node.getNextSibling()) {
- //System.out.println("getNode: " + name + " " + node.getNodeName());
- if( name.equals( node.getNodeName() ) ) {
- return node;
- }
- }
- return null;
- }
-
- /** Get the first child's content ( i.e. it's included TEXT node )
- */
- public static String getChildContent( Node parent, String name ) {
- Node first=parent.getFirstChild();
- if( first==null ) return null;
- for (Node node = first; node != null;
- node = node.getNextSibling()) {
- //System.out.println("getNode: " + name + " " + node.getNodeName());
- if( name.equals( node.getNodeName() ) ) {
- return getContent( node );
- }
- }
- return null;
- }
-
- /** Get the node in the list of siblings
- */
- public static Node getNext( Node current ) {
- Node first=current.getNextSibling();
- String name=current.getNodeName();
- if( first==null ) return null;
- for (Node node = first; node != null;
- node = node.getNextSibling()) {
- //System.out.println("getNode: " + name + " " + node.getNodeName());
- if( name.equals( node.getNodeName() ) ) {
- return node;
- }
- }
- return null;
- }
-
- public static class NullResolver implements EntityResolver {
- public InputSource resolveEntity (String publicId,
- String systemId)
- throws SAXException, IOException
- {
- if (log.isDebugEnabled())
- log.debug("ResolveEntity: " + publicId + " " + systemId);
- return new InputSource(new StringReader(""));
- }
- }
-
- public static Document readXml(File xmlF)
- throws SAXException, IOException, ParserConfigurationException
- {
- if( ! xmlF.exists() ) {
- log.error("No xml file " + xmlF );
- return null;
- }
- DocumentBuilderFactory dbf =
- DocumentBuilderFactory.newInstance();
-
- dbf.setValidating(false);
- dbf.setIgnoringComments(false);
- dbf.setIgnoringElementContentWhitespace(true);
- //dbf.setCoalescing(true);
- //dbf.setExpandEntityReferences(true);
-
- DocumentBuilder db = null;
- db = dbf.newDocumentBuilder();
- db.setEntityResolver( new NullResolver() );
-
- // db.setErrorHandler( new MyErrorHandler());
-
- Document doc = db.parse(xmlF);
- return doc;
- }
-
-}
+++ /dev/null
-/*
- * 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.jk.core;
-
-import java.io.IOException;
-
-import org.apache.coyote.Request;
-
-/**
- * A Channel represents a connection point to the outside world.
- *
- * @author Bill Barker
- */
-
-public interface JkChannel {
-
-
- /**
- * Return the identifying name of this Channel.
- */
- public String getChannelName();
-
- /**
- * Send a message back to the client.
- * @param msg The message to send.
- * @param ep The connection point for this request.
- */
- public int send(Msg msg, MsgContext ep) throws IOException;
-
- /**
- * Recieve a message from the client.
- * @param msg The place to recieve the data into.
- * @param ep The connection point for this request.
- */
- public int receive(Msg msg, MsgContext ep) throws IOException;
-
- /**
- * Flush the data to the client.
- */
- public int flush(Msg msg, MsgContext ep) throws IOException;
-
- /**
- * Invoke the request chain.
- */
- public int invoke(Msg msg, MsgContext ep) throws IOException;
-
- /**
- * Confirm that a shutdown request was recieved form us.
- */
- public boolean isSameAddress(MsgContext ep);
-
- /**
- * Register a new Request in the Request pool.
- */
- public void registerRequest(Request req, MsgContext ep, int count);
-
- /**
- * Create a new request endpoint.
- */
- public MsgContext createMsgContext();
-
-}
+++ /dev/null
-/*
- * 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.jk.core;
-
-import java.io.IOException;
-import java.util.Properties;
-
-import javax.management.MBeanRegistration;
-import javax.management.MBeanServer;
-import javax.management.Notification;
-import javax.management.NotificationListener;
-import javax.management.ObjectName;
-
-import org.apache.tomcat.util.modeler.Registry;
-
-/**
- *
- * @author Costin Manolache
- */
-public class JkHandler implements MBeanRegistration, NotificationListener {
- public static final int OK=0;
- public static final int LAST=1;
- public static final int ERROR=2;
-
- protected Properties properties=new Properties();
- protected WorkerEnv wEnv;
- protected JkHandler next;
- protected String nextName=null;
- protected String name;
- protected int id;
-
- // XXX Will be replaced with notes and (configurable) ids
- // Each represents a 'chain' - similar with ActionCode in Coyote ( the concepts
- // will be merged ).
- public static final int HANDLE_RECEIVE_PACKET = 10;
- public static final int HANDLE_SEND_PACKET = 11;
- public static final int HANDLE_FLUSH = 12;
- public static final int HANDLE_THREAD_END = 13;
-
- public void setWorkerEnv( WorkerEnv we ) {
- this.wEnv=we;
- }
-
- /** Set the name of the handler. Will allways be called by
- * worker env after creating the worker.
- */
- public void setName(String s ) {
- name=s;
- }
-
- public String getName() {
- return name;
- }
-
- /** Set the id of the worker. We use an id for faster dispatch.
- * Since we expect a decent number of handler in system, the
- * id is unique - that means we may have to allocate bigger
- * dispatch tables. ( easy to fix if needed )
- */
- public void setId( int id ) {
- this.id=id;
- }
-
- public int getId() {
- return id;
- }
-
- /** Catalina-style "recursive" invocation.
- * A chain is used for Apache/3.3 style iterative invocation.
- */
- public void setNext( JkHandler h ) {
- next=h;
- }
-
- public void setNext( String s ) {
- nextName=s;
- }
-
- public String getNext() {
- if( nextName==null ) {
- if( next!=null)
- nextName=next.getName();
- }
- return nextName;
- }
-
- /** Should register the request types it can handle,
- * same style as apache2.
- */
- public void init() throws IOException {
- }
-
- /** Clean up and stop the handler
- */
- public void destroy() throws IOException {
- }
-
- public MsgContext createMsgContext() {
- return new MsgContext(8*1024);
- }
-
- public MsgContext createMsgContext(int bsize) {
- return new MsgContext(bsize);
- }
-
- public int invoke(Msg msg, MsgContext mc ) throws IOException {
- return OK;
- }
-
- public void setProperty( String name, String value ) {
- properties.put( name, value );
- }
-
- public String getProperty( String name ) {
- return properties.getProperty(name) ;
- }
-
- /** Experimental, will be replaced. This allows handlers to be
- * notified when other handlers are added.
- */
- public void addHandlerCallback( JkHandler w ) {
-
- }
-
- public void handleNotification(Notification notification, Object handback)
- {
-// BaseNotification bNot=(BaseNotification)notification;
-// int code=bNot.getCode();
-//
-// MsgContext ctx=(MsgContext)bNot.getSource();
-
-
- }
-
- 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 oname) throws Exception {
- this.oname=oname;
- mserver=server;
- domain=oname.getDomain();
- if( name==null ) {
- name=oname.getKeyProperty("name");
- }
-
- // we need to create a workerEnv or set one.
- ObjectName wEnvName=new ObjectName(domain + ":type=JkWorkerEnv");
- if ( wEnv == null ) {
- wEnv=new WorkerEnv();
- }
- if( ! mserver.isRegistered(wEnvName )) {
- Registry.getRegistry(null, null).registerComponent(wEnv, wEnvName, null);
- }
- mserver.invoke( wEnvName, "addHandler",
- new Object[] {name, this},
- new String[] {"java.lang.String",
- "org.apache.jk.core.JkHandler"});
- return oname;
- }
-
- public void postRegister(Boolean registrationDone) {
- }
-
- public void preDeregister() throws Exception {
- }
-
- public void postDeregister() {
- }
-
- public void pause() throws Exception {
- }
-
- public void resume() throws Exception {
- }
-
-}
+++ /dev/null
-/*
- * 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.jk.core;
-
-import java.io.IOException;
-
-import org.apache.tomcat.util.buf.ByteChunk;
-import org.apache.tomcat.util.buf.MessageBytes;
-
-
-/**
- * A single packet for communication between the web server and the
- * container.
- *
- * In a more generic sense, it's the event that drives the processing chain.
- * XXX Use Event, make Msg a particular case.
- *
- * @author Henri Gomez [hgomez@apache.org]
- * @author Dan Milstein [danmil@shore.net]
- * @author Keith Wannamaker [Keith@Wannamaker.org]
- * @author Kevin Seguin
- * @author Costin Manolache
- */
-public abstract class Msg {
-
-
-
- /**
- * Prepare this packet for accumulating a message from the container to
- * the web server. Set the write position to just after the header
- * (but leave the length unwritten, because it is as yet unknown).
- */
- public abstract void reset();
-
- /**
- * For a packet to be sent to the web server, finish the process of
- * accumulating data and write the length of the data payload into
- * the header.
- */
- public abstract void end();
-
- public abstract void appendInt( int val );
-
- public abstract void appendByte( int val );
-
- public abstract void appendLongInt( int val );
-
- /**
- */
- public abstract void appendBytes(MessageBytes mb) throws IOException;
-
- public abstract void appendByteChunk(ByteChunk bc) throws IOException;
-
- /**
- * Copy a chunk of bytes into the packet, starting at the current
- * write position. The chunk of bytes is encoded with the length
- * in two bytes first, then the data itself, and finally a
- * terminating \0 (which is <B>not</B> included in the encoded
- * length).
- *
- * @param b The array from which to copy bytes.
- * @param off The offset into the array at which to start copying
- * @param numBytes The number of bytes to copy.
- */
- public abstract void appendBytes( byte b[], int off, int numBytes );
-
- /**
- * Read an integer from packet, and advance the read position past
- * it. Integers are encoded as two unsigned bytes with the
- * high-order byte first, and, as far as I can tell, in
- * little-endian order within each byte.
- */
- public abstract int getInt();
-
- public abstract int peekInt();
-
- public abstract byte getByte();
-
- public abstract byte peekByte();
-
- public abstract void getBytes(MessageBytes mb);
-
- /**
- * Copy a chunk of bytes from the packet into an array and advance
- * the read position past the chunk. See appendBytes() for details
- * on the encoding.
- *
- * @return The number of bytes copied.
- */
- public abstract int getBytes(byte dest[]);
-
- /**
- * Read a 32 bits integer from packet, and advance the read position past
- * it. Integers are encoded as four unsigned bytes with the
- * high-order byte first, and, as far as I can tell, in
- * little-endian order within each byte.
- */
- public abstract int getLongInt();
-
- public abstract int getHeaderLength();
-
- public abstract int processHeader();
-
- public abstract byte[] getBuffer();
-
- public abstract int getLen();
-
- public abstract void dump(String msg);
-
- /* -------------------- Utilities -------------------- */
- // XXX Move to util package
-
- public static String hexLine( byte buf[], int start, int len ) {
- StringBuffer sb=new StringBuffer();
- for( int i=start; i< start+16 ; i++ ) {
- if( i < len + 4)
- sb.append( hex( buf[i] ) + " ");
- else
- sb.append( " " );
- }
- sb.append(" | ");
- for( int i=start; i < start+16 && i < len + 4; i++ ) {
- if( ! Character.isISOControl( (char)buf[i] ))
- sb.append( new Character((char)buf[i]) );
- else
- sb.append( "." );
- }
- return sb.toString();
- }
-
- private static String hex( int x ) {
- // if( x < 0) x=256 + x;
- String h=Integer.toHexString( x );
- if( h.length() == 1 ) h = "0" + h;
- return h.substring( h.length() - 2 );
- }
-
-
-}
+++ /dev/null
-/*
- * 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.jk.core;
-
-import java.io.IOException;
-import java.io.ByteArrayInputStream;
-import java.net.InetAddress;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-
-import org.apache.coyote.ActionCode;
-import org.apache.coyote.ActionHook;
-import org.apache.coyote.Request;
-import org.apache.coyote.Response;
-
-import org.apache.tomcat.util.buf.C2BConverter;
-import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.buf.ByteChunk;
-import org.apache.tomcat.util.net.SSLSupport;
-import org.apache.jk.common.JkInputStream;
-
-
-/**
- *
- * @author Henri Gomez [hgomez@apache.org]
- * @author Dan Milstein [danmil@shore.net]
- * @author Keith Wannamaker [Keith@Wannamaker.org]
- * @author Kevin Seguin
- * @author Costin Manolache
- */
-public class MsgContext implements ActionHook {
- private static org.apache.juli.logging.Log log =
- org.apache.juli.logging.LogFactory.getLog(MsgContext.class);
- private static org.apache.juli.logging.Log logTime=
- org.apache.juli.logging.LogFactory.getLog( "org.apache.jk.REQ_TIME" );
-
- private int type;
- private Object notes[]=new Object[32];
- private JkHandler next;
- private JkChannel source;
- private JkInputStream jkIS;
- private C2BConverter c2b;
- private Request req;
- private WorkerEnv wEnv;
- private Msg msgs[]=new Msg[10];
- private int status=0;
- // Control object
- private Object control;
-
- // Application managed, like notes
- private long timers[]=new long[20];
-
- // The context can be used by JNI components as well
- private long jkEndpointP;
- private long xEnvP;
-
- // Temp: use notes and dynamic strings
- public static final int TIMER_RECEIVED=0;
- public static final int TIMER_PRE_REQUEST=1;
- public static final int TIMER_POST_REQUEST=2;
-
- // Status codes
- public static final int JK_STATUS_NEW=0;
- public static final int JK_STATUS_HEAD=1;
- public static final int JK_STATUS_CLOSED=2;
- public static final int JK_STATUS_ERROR=3;
-
- public MsgContext(int bsize) {
- try {
- c2b = new C2BConverter("iso-8859-1");
- } catch(IOException iex) {
- log.warn("Can't happen", iex);
- }
- jkIS = new JkInputStream(this, bsize);
- }
- /**
- * @deprecated
- */
- public MsgContext() {
- this(8*1024);
- }
-
- public final Object getNote( int id ) {
- return notes[id];
- }
-
- public final void setNote( int id, Object o ) {
- notes[id]=o;
- }
-
- /** The id of the chain */
- public final int getType() {
- return type;
- }
-
- public final void setType(int i) {
- type=i;
- }
-
- public final void setLong( int i, long l) {
- timers[i]=l;
- }
-
- public final long getLong( int i) {
- return timers[i];
- }
-
- // Common attributes ( XXX should be notes for flexibility ? )
-
- public final WorkerEnv getWorkerEnv() {
- return wEnv;
- }
-
- public final void setWorkerEnv( WorkerEnv we ) {
- this.wEnv=we;
- }
-
- public final JkChannel getSource() {
- return source;
- }
-
- public final void setSource(JkChannel ch) {
- this.source=ch;
- }
-
- public final int getStatus() {
- return status;
- }
-
- public final void setStatus( int s ) {
- status=s;
- }
-
- public final JkHandler getNext() {
- return next;
- }
-
- public final void setNext(JkHandler ch) {
- this.next=ch;
- }
-
- /** The high level request object associated with this context
- */
- public final void setRequest( Request req ) {
- this.req=req;
- req.setInputBuffer(jkIS);
- Response res = req.getResponse();
- res.setOutputBuffer(jkIS);
- res.setHook(this);
- }
-
- public final Request getRequest() {
- return req;
- }
-
- /** The context may store a number of messages ( buffers + marshalling )
- */
- public final Msg getMsg(int i) {
- return msgs[i];
- }
-
- public final void setMsg(int i, Msg msg) {
- this.msgs[i]=msg;
- }
-
- public final C2BConverter getConverter() {
- return c2b;
- }
-
- public final void setConverter(C2BConverter c2b) {
- this.c2b = c2b;
- }
-
- public final boolean isLogTimeEnabled() {
- return logTime.isDebugEnabled();
- }
-
- public JkInputStream getInputStream() {
- return jkIS;
- }
-
- /** Each context contains a number of byte[] buffers used for communication.
- * The C side will contain a char * equivalent - both buffers are long-lived
- * and recycled.
- *
- * This will be called at init time. A long-lived global reference to the byte[]
- * will be stored in the C context.
- */
- public byte[] getBuffer( int id ) {
- // We use a single buffer right now.
- if( msgs[id]==null ) {
- return null;
- }
- return msgs[id].getBuffer();
- }
-
- /** Invoke a java hook. The xEnv is the representation of the current execution
- * environment ( the jni_env_t * )
- */
- public int execute() throws IOException {
- int status=next.invoke(msgs[0], this);
- return status;
- }
-
- // -------------------- Jni support --------------------
-
- /** Store native execution context data when this handler is called
- * from JNI. This will change on each call, represent temproary
- * call data.
- */
- public void setJniEnv( long xEnvP ) {
- this.xEnvP=xEnvP;
- }
-
- public long getJniEnv() {
- return xEnvP;
- }
-
- /** The long-lived JNI context associated with this java context.
- * The 2 share pointers to buffers and cache data to avoid expensive
- * jni calls.
- */
- public void setJniContext( long cContext ) {
- this.jkEndpointP=cContext;
- }
-
- public long getJniContext() {
- return jkEndpointP;
- }
-
- public Object getControl() {
- return control;
- }
-
- public void setControl(Object control) {
- this.control = control;
- }
-
- // -------------------- Coyote Action implementation --------------------
-
- public void action(ActionCode actionCode, Object param) {
- if( actionCode==ActionCode.ACTION_COMMIT ) {
- if( log.isDebugEnabled() ) log.debug("COMMIT " );
- Response res=(Response)param;
-
- if( res.isCommitted() ) {
- if( log.isDebugEnabled() )
- log.debug("Response already committed " );
- } else {
- try {
- jkIS.appendHead( res );
- } catch(IOException iex) {
- log.warn("Unable to send headers",iex);
- setStatus(JK_STATUS_ERROR);
- }
- }
- } else if( actionCode==ActionCode.ACTION_RESET ) {
- if( log.isDebugEnabled() )
- log.debug("RESET " );
-
- } else if( actionCode==ActionCode.ACTION_CLIENT_FLUSH ) {
- if( log.isDebugEnabled() ) log.debug("CLIENT_FLUSH " );
- Response res = (Response)param;
- if(!res.isCommitted()) {
- action(ActionCode.ACTION_COMMIT, res);
- }
- try {
- source.flush( null, this );
- } catch(IOException iex) {
- // This is logged elsewhere, so debug only here
- log.debug("Error during flush",iex);
- res.setErrorException(iex);
- setStatus(JK_STATUS_ERROR);
- }
-
- } else if( actionCode==ActionCode.ACTION_CLOSE ) {
- if( log.isDebugEnabled() ) log.debug("CLOSE " );
-
- Response res=(Response)param;
- if( getStatus()== JK_STATUS_CLOSED || getStatus() == JK_STATUS_ERROR) {
- // Double close - it may happen with forward
- if( log.isDebugEnabled() ) log.debug("Double CLOSE - forward ? " + res.getRequest().requestURI() );
- return;
- }
-
- if( !res.isCommitted() )
- this.action( ActionCode.ACTION_COMMIT, param );
- try {
- jkIS.endMessage();
- } catch(IOException iex) {
- log.debug("Error sending end packet",iex);
- setStatus(JK_STATUS_ERROR);
- }
- if(getStatus() != JK_STATUS_ERROR) {
- setStatus(JK_STATUS_CLOSED );
- }
-
- if( logTime.isDebugEnabled() )
- logTime(res.getRequest(), res);
- } else if( actionCode==ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) {
- Request req=(Request)param;
-
- // Extract SSL certificate information (if requested)
- MessageBytes certString = (MessageBytes)req.getNote(WorkerEnv.SSL_CERT_NOTE);
- if( certString != null && !certString.isNull() ) {
- ByteChunk certData = certString.getByteChunk();
- ByteArrayInputStream bais =
- new ByteArrayInputStream(certData.getBytes(),
- certData.getStart(),
- certData.getLength());
-
- // Fill the elements.
- X509Certificate jsseCerts[] = null;
- try {
- CertificateFactory cf =
- CertificateFactory.getInstance("X.509");
- while(bais.available() > 0) {
- X509Certificate cert = (X509Certificate)
- cf.generateCertificate(bais);
- if(jsseCerts == null) {
- jsseCerts = new X509Certificate[1];
- jsseCerts[0] = cert;
- } else {
- X509Certificate [] temp = new X509Certificate[jsseCerts.length+1];
- System.arraycopy(jsseCerts,0,temp,0,jsseCerts.length);
- temp[jsseCerts.length] = cert;
- jsseCerts = temp;
- }
- }
- } catch(java.security.cert.CertificateException e) {
- log.error("Certificate convertion failed" , e );
- return;
- }
-
- req.setAttribute(SSLSupport.CERTIFICATE_KEY,
- jsseCerts);
- }
-
- } else if( actionCode==ActionCode.ACTION_REQ_HOST_ATTRIBUTE ) {
- Request req=(Request)param;
-
- // If remoteHost not set by JK, get it's name from it's remoteAddr
- if( req.remoteHost().isNull()) {
- try {
- req.remoteHost().setString(InetAddress.getByName(
- req.remoteAddr().toString()).
- getHostName());
- } catch(IOException iex) {
- if(log.isDebugEnabled())
- log.debug("Unable to resolve "+req.remoteAddr());
- }
- }
- } else if( actionCode==ActionCode.ACTION_ACK ) {
- if( log.isTraceEnabled() )
- log.trace("ACK " );
- } else if ( actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY ) {
- if( log.isTraceEnabled() )
- log.trace("Replay ");
- ByteChunk bc = (ByteChunk)param;
- req.setContentLength(bc.getLength());
- jkIS.setReplay(bc);
- }
- }
-
-
- private void logTime(Request req, Response res ) {
- // called after the request
- // org.apache.coyote.Request req=(org.apache.coyote.Request)param;
- // Response res=req.getResponse();
- String uri=req.requestURI().toString();
- if( uri.indexOf( ".gif" ) >0 ) return;
-
- setLong( MsgContext.TIMER_POST_REQUEST, System.currentTimeMillis());
- long t1= getLong( MsgContext.TIMER_PRE_REQUEST ) -
- getLong( MsgContext.TIMER_RECEIVED );
- long t2= getLong( MsgContext.TIMER_POST_REQUEST ) -
- getLong( MsgContext.TIMER_PRE_REQUEST );
-
- logTime.debug("Time pre=" + t1 + "/ service=" + t2 + " " +
- res.getContentLength() + " " +
- uri );
- }
-
- public void recycle() {
- jkIS.recycle();
- }
-}
+++ /dev/null
-/*
- * 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.jk.core;
-
-import java.util.Hashtable;
-import javax.management.ObjectName;
-
-/**
- * The controller object. It manages all other jk objects, acting as the root of
- * the jk object model.
- *
- * @author Gal Shachor
- * @author Henri Gomez [hgomez@apache.org]
- * @author Dan Milstein [danmil@shore.net]
- * @author Keith Wannamaker [Keith@Wannamaker.org]
- * @author Kevin Seguin
- * @author Costin Manolache
- */
-public class WorkerEnv {
-
- Hashtable<Object, Object> properties;
-
- public static final int ENDPOINT_NOTE=0;
- public static final int REQUEST_NOTE=1;
- public static final int SSL_CERT_NOTE=16;
- int noteId[]=new int[4];
- String noteName[][]=new String[4][];
- private Object notes[]=new Object[32];
-
- Hashtable<String, JkHandler> handlersMap =
- new Hashtable<String, JkHandler>();
- JkHandler handlersTable[]=new JkHandler[20];
- int handlerCount=0;
-
- // base dir for the jk webapp
- String home;
- int localId=0;
-
- public WorkerEnv() {
- for( int i=0; i<noteId.length; i++ ) {
- noteId[i]=7;
- noteName[i]=new String[20];
- }
- }
-
- public void setLocalId(int id) {
- localId=id;
- }
-
- public int getLocalId() {
- return localId;
- }
-
- public void setJkHome( String s ) {
- home=s;
- }
-
- public String getJkHome() {
- return home;
- }
-
- public final Object getNote(int i ) {
- return notes[i];
- }
-
- public final void setNote(int i, Object o ) {
- notes[i]=o;
- }
-
- public int getNoteId( int type, String name ) {
- for( int i=0; i<noteId[type]; i++ ) {
- if( name.equals( noteName[type][i] ))
- return i;
- }
- int id=noteId[type]++;
- noteName[type][id]=name;
- return id;
- }
-
- public void addHandler( String name, JkHandler w ) {
- JkHandler oldH = getHandler(name);
- if(oldH == w) {
- // Already added
- return;
- }
- w.setWorkerEnv( this );
- w.setName( name );
- handlersMap.put( name, w );
- if( handlerCount > handlersTable.length ) {
- JkHandler newT[]=new JkHandler[ 2 * handlersTable.length ];
- System.arraycopy( handlersTable, 0, newT, 0, handlersTable.length );
- handlersTable=newT;
- }
- if(oldH == null) {
- handlersTable[handlerCount]=w;
- w.setId( handlerCount );
- handlerCount++;
- } else {
- handlersTable[oldH.getId()]=w;
- w.setId(oldH.getId());
- }
-
- // Notify all other handlers of the new one
- // XXX Could be a Coyote action ?
- for( int i=0; i< handlerCount ; i++ ) {
- handlersTable[i].addHandlerCallback( w );
- }
- }
-
- public final JkHandler getHandler( String name ) {
- return handlersMap.get(name);
- }
-
- public final JkHandler getHandler( int id ) {
- return handlersTable[id];
- }
-
- public final int getHandlerCount() {
- return handlerCount;
- }
-
- public ObjectName[] getHandlersObjectName() {
-
- ObjectName onames[]=new ObjectName[ handlerCount ];
- for( int i=0; i<handlerCount; i++ ) {
- onames[i]=handlersTable[i].getObjectName();
- }
- return onames;
- }
-
-}
+++ /dev/null
-<!--
- 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.
--->
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
-<head>
- <title></title>
-</head>
-<body>
-<h2>Jk2 interfaces</h2>
-<p>Core interfaces for jk2, similar with the interfaces defined in the C
-side ( jk2/include ).<br>
-</p>
-<p>The implementations are in common/ and server/.<br>
-</p>
-<p><br>
-</p>
-</body>
-</html>
+++ /dev/null
-<?xml version="1.0"?>
-<!--
- 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.
--->
-<!DOCTYPE mbeans-descriptors PUBLIC
- "-//Apache Software Foundation//DTD Model MBeans Configuration File"
- "http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">
-
-<!--
- Descriptions of JMX MBeans for jk
- -->
-
-<mbeans-descriptors>
-
- <mbean name="ChannelSocket"
- description="Socket channel"
- domain="Catalina"
- group="Jk"
- type="org.apache.jk.common.ChannelSocket">
-
- <attribute name="port"
- description="The port number on which we listen for ajp13 requests"
- type="int"/>
- <attribute name="maxPort"
- description="The max port number on which we listen for ajp13 requests"
- type="int"/>
- <attribute name="address"
- description="The IP address on which to bind"
- type="java.lang.String"/>
- <attribute name="maxSpareThreads"
- description="The maximum number of unused request processing threads"
- type="int"/>
- <attribute name="maxThreads"
- description="The maximum number of request processing threads to be created"
- type="int"/>
- <attribute name="minSpareThreads"
- description="The number of request processing threads that will be created"
- type="int"/>
- <attribute name="tcpNoDelay"
- description="Should we use TCP no delay?"
- type="boolean"/>
- <attribute name="soLinger"
- description="Linger value on the incoming connection"
- type="int"/>
- <attribute name="soTimeout"
- description="Socket timeout"
- type="int"/>
- <attribute name="requestCount"
- description="current request count"
- type="int"
- writeable="false"/>
- <attribute name="daemon"
- description="are worker threads on daemon mode"
- type="boolean"
- writeable="false"/>
- <attribute name="packetSize"
- description="The maximum AJP packet size"
- type="int" />
-
- <operation name="start"
- description="Start, if server socket no create call init"
- impact="ACTION"
- returnType="void" />
- <operation name="stop"
- description="Stop"
- impact="ACTION"
- returnType="void" />
- <operation name="pause"
- description="Pause ajp socket, no new connection accepted"
- impact="ACTION"
- returnType="void"/>
- <operation name="resume"
- description="Resume socket for new connections"
- impact="ACTION"
- returnType="void"/>
- <operation name="reinit"
- description="Init and Destroy"
- impact="ACTION"
- returnType="void" />
- <operation name="init"
- description="Init"
- impact="ACTION"
- returnType="void" />
- <operation name="destroy"
- description="Destroy"
- impact="ACTION"
- returnType="void" />
- <operation name="resetCounters"
- description="reset request counter"
- impact="ACTION"
- returnType="void"/>
-
-
- </mbean>
-
- <mbean name="JkWorkerEnv"
- description="Worker env for jk"
- domain="Catalina"
- group="Jk"
- type="org.apache.jk.core.WorkerEnv">
-
- <attribute name="localId"
- description="If automatic port allocation is enabled, ChannelSocket will allocate ports sequentially. This is the sequence number"
- type="java.lang.Integer"/>
-
- <attribute name="jkHome"
- description="Base directory for jk"
- type="java.lang.String"/>
-
- <attribute name="managedResource"
- description="Access to the object"
- type="java.lang.Object" writeable="false" />
-
- <attribute name="handlersObjectName"
- description="List of all jk handlers"
- type="[Ljavax.management.ObjectName;"/>
-
- <operation name="addHandler"
- description="add a jk component"
- returnType="void">
- <parameter name="name"
- description="local name"
- type="java.lang.String"/>
- <parameter name="handler"
- description="handler"
- type="org.apache.jk.core.JkHandler"/>
- </operation>
-
- </mbean>
-
- <!-- Native connectors -->
- <mbean name="JkAjp13"
- description="native Ajp13 connector"
- domain="Catalina"
- group="Jk"
- type="org.apache.jk.modjk.ajp13">
-
- <attribute name="Id"
- description="Internal id"
- type="java.lang.String"/>
-
- <attribute name="disabled"
- description="State"
- type="java.lang.Integer"/>
-
- <attribute name="ver"
- description="Generation"
- type="java.lang.Integer"/>
-
- <attribute name="debug"
- description="Debug level"
- type="java.lang.Integer"/>
-
- <attribute name="lb_factor"
- description=""
- type="java.lang.Integer"/>
- <attribute name="lb_value"
- description=""
- type="java.lang.Integer"/>
- <attribute name="epCount"
- description=""
- type="java.lang.Integer"/>
- <attribute name="graceful"
- description=""
- type="java.lang.Integer"/>
-
- <attribute name="route"
- description=""
- type="java.lang.String"/>
-
- </mbean>
-
- <mbean name="JkChannelSocket"
- description="native Ajp13 connector"
- domain="Catalina"
- group="Jk"
- type="org.apache.jk.modjk.channel.socket">
-
- <attribute name="Id"
- description="Internal id"
- type="java.lang.String"/>
-
- <attribute name="disabled"
- description="State"
- type="java.lang.Integer"/>
-
- <attribute name="ver"
- description="Generation"
- type="java.lang.Integer"/>
-
- <attribute name="debug"
- description="Debug level"
- type="java.lang.Integer"/>
-
- </mbean>
-
- <mbean name="JkWorkerEnv"
- description=""
- domain="Catalina"
- group="Jk"
- type="org.apache.jk.modjk.workerEnv">
-
- <attribute name="Id"
- description="Internal id"
- type="java.lang.String"/>
-
- <attribute name="disabled"
- description="State"
- type="java.lang.Integer"/>
-
- <attribute name="ver"
- description="Generation"
- type="java.lang.Integer"/>
-
- <attribute name="debug"
- description="Debug level"
- type="java.lang.Integer"/>
-
- </mbean>
-
- <mbean name="JkLoggerApache2"
- description=""
- domain="Catalina"
- group="Jk"
- type="org.apache.jk.modjk.logger.apache2">
- <attribute name="Id"
- description="Internal id"
- type="java.lang.String"/>
-
- <attribute name="disabled"
- description="State"
- type="java.lang.Integer"/>
-
- <attribute name="ver"
- description="Generation"
- type="java.lang.Integer"/>
-
- <attribute name="debug"
- description="Debug level"
- type="java.lang.Integer"/>
-
-
- </mbean>
-
- <mbean name="JkUriMap"
- description=""
- domain="Catalina"
- group="Jk"
- type="org.apache.jk.modjk.uriMap">
- <attribute name="Id"
- description="Internal id"
- type="java.lang.String"/>
-
- <attribute name="disabled"
- description="State"
- type="java.lang.Integer"/>
-
- <attribute name="ver"
- description="Generation"
- type="java.lang.Integer"/>
-
- <attribute name="debug"
- description="Debug level"
- type="java.lang.Integer"/>
-
-
- </mbean>
-
- <mbean name="JkConfig"
- description=""
- domain="Catalina"
- group="Jk"
- type="org.apache.jk.modjk.config">
- <attribute name="Id"
- description="Internal id"
- type="java.lang.String"/>
-
- <attribute name="disabled"
- description="State"
- type="java.lang.Integer"/>
-
- <attribute name="ver"
- description="Generation"
- type="java.lang.Integer"/>
-
- <attribute name="debug"
- description="Debug level"
- type="java.lang.Integer"/>
-
- <attribute name="file"
- description="Config file"
- type="java.lang.String"/>
-
- </mbean>
- <mbean name="JkShm"
- description=""
- domain="Catalina"
- group="Jk"
- type="org.apache.jk.modjk.shm">
- <attribute name="Id"
- description="Internal id"
- type="java.lang.String"/>
-
- <attribute name="disabled"
- description="State"
- type="java.lang.Integer"/>
-
- <attribute name="ver"
- description="Generation"
- type="java.lang.Integer"/>
-
- <attribute name="debug"
- description="Debug level"
- type="java.lang.Integer"/>
-
-
- </mbean>
- <mbean name="JkUri"
- description=""
- domain="Catalina"
- group="Jk"
- type="org.apache.jk.modjk.uri">
-
- <attribute name="Id"
- description="Internal id"
- type="java.lang.String"/>
-
- <attribute name="disabled"
- description="State"
- type="java.lang.Integer"/>
-
- <attribute name="ver"
- description="Generation"
- type="java.lang.Integer"/>
-
- <attribute name="debug"
- description="Debug level"
- type="java.lang.Integer"/>
-
- <attribute name="host"
- description="Uri components"
- type="java.lang.String"/>
- <attribute name="uri"
- description="Uri"
- type="java.lang.String"/>
- <attribute name="path"
- description="Uri"
- type="java.lang.String"/>
-
- </mbean>
-
- <mbean name="JkVm"
- description=""
- domain="Catalina"
- group="Jk"
- type="org.apache.jk.modjk.vm">
- <attribute name="Id"
- description="Internal id"
- type="java.lang.String"/>
-
- <attribute name="disabled"
- description="State"
- type="java.lang.Integer"/>
-
- <attribute name="ver"
- description="Generation"
- type="java.lang.Integer"/>
-
- <attribute name="debug"
- description="Debug level"
- type="java.lang.Integer"/>
-
-
- </mbean>
-
- <mbean name="JkChannelUn"
- description=""
- domain="Catalina"
- group="Jk"
- type="org.apache.jk.modjk.channel.un">
- <attribute name="Id"
- description="Internal id"
- type="java.lang.String"/>
-
- <attribute name="disabled"
- description="State"
- type="java.lang.Integer"/>
-
- <attribute name="ver"
- description="Generation"
- type="java.lang.Integer"/>
-
- <attribute name="debug"
- description="Debug level"
- type="java.lang.Integer"/>
-
-
- </mbean>
-
- <mbean name="JkChannelJni"
- description=""
- domain="Catalina"
- group="Jk"
- type="org.apache.jk.modjk.channel.jni">
- <attribute name="Id"
- description="Internal id"
- type="java.lang.String"/>
-
- <attribute name="disabled"
- description="State"
- type="java.lang.Integer"/>
-
- <attribute name="ver"
- description="Generation"
- type="java.lang.Integer"/>
-
- <attribute name="debug"
- description="Debug level"
- type="java.lang.Integer"/>
-
-
- </mbean>
-
- <mbean name="JkWorkerJni"
- description=""
- domain="Catalina"
- group="Jk"
- type="org.apache.jk.modjk.worker.jni">
- <attribute name="Id"
- description="Internal id"
- type="java.lang.String"/>
-
- <attribute name="disabled"
- description="State"
- type="java.lang.Integer"/>
-
- <attribute name="ver"
- description="Generation"
- type="java.lang.Integer"/>
-
- <attribute name="debug"
- description="Debug level"
- type="java.lang.Integer"/>
-
-
- </mbean>
-
- <mbean name="JkStatus"
- description=""
- domain="Catalina"
- group="Jk"
- type="org.apache.jk.modjk.status">
- <attribute name="Id"
- description="Internal id"
- type="java.lang.String"/>
-
- <attribute name="disabled"
- description="State"
- type="java.lang.Integer"/>
-
- <attribute name="ver"
- description="Generation"
- type="java.lang.Integer"/>
-
- <attribute name="debug"
- description="Debug level"
- type="java.lang.Integer"/>
-
-
- </mbean>
- <mbean name="JkHandlerResponse"
- description=""
- domain="Catalina"
- group="Jk"
- type="org.apache.jk.modjk.handler.response">
- <attribute name="Id"
- description="Internal id"
- type="java.lang.String"/>
-
- <attribute name="disabled"
- description="State"
- type="java.lang.Integer"/>
-
- <attribute name="ver"
- description="Generation"
- type="java.lang.Integer"/>
-
- <attribute name="debug"
- description="Debug level"
- type="java.lang.Integer"/>
-
-
- </mbean>
- <mbean name="JkHandlerLogon"
- description=""
- domain="Catalina"
- group="Jk"
- type="org.apache.jk.modjk.handler.logon">
- <attribute name="Id"
- description="Internal id"
- type="java.lang.String"/>
-
- <attribute name="disabled"
- description="State"
- type="java.lang.Integer"/>
-
- <attribute name="ver"
- description="Generation"
- type="java.lang.Integer"/>
-
- <attribute name="debug"
- description="Debug level"
- type="java.lang.Integer"/>
-
-
- </mbean>
-
- <mbean name="JkLb"
- description=""
- domain="Catalina"
- group="Jk"
- type="org.apache.jk.modjk.lb">
-
- <attribute name="Id"
- description="Internal id"
- type="java.lang.String"/>
-
- <attribute name="disabled"
- description="State"
- type="java.lang.Integer"/>
-
- <attribute name="ver"
- description="Generation"
- type="java.lang.Integer"/>
-
- <attribute name="debug"
- description="Debug level"
- type="java.lang.Integer"/>
-
- </mbean>
-
-
-
-</mbeans-descriptors>
+++ /dev/null
-/*
- * 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.jk.server;
-
-import java.io.IOException;
-import java.util.Iterator;
-
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
-import org.apache.coyote.Adapter;
-import org.apache.coyote.ProtocolHandler;
-import org.apache.coyote.Request;
-import org.apache.coyote.Response;
-import org.apache.coyote.RequestInfo;
-import org.apache.coyote.Constants;
-import org.apache.jk.core.JkHandler;
-import org.apache.jk.core.Msg;
-import org.apache.jk.core.MsgContext;
-import org.apache.tomcat.util.modeler.Registry;
-
-/** Plugs Jk into Coyote. Must be named "type=JkHandler,name=container"
- *
- * jmx:notification-handler name="org.apache.jk.SEND_PACKET
- * jmx:notification-handler name="org.apache.coyote.ACTION_COMMIT
- */
-public class JkCoyoteHandler extends JkHandler implements ProtocolHandler {
- protected static org.apache.juli.logging.Log log
- = org.apache.juli.logging.LogFactory.getLog(JkCoyoteHandler.class);
- // Set debug on this logger to see the container request time
-
- // ----------------------------------------------------------- DoPrivileged
- private boolean paused = false;
- int epNote;
- Adapter adapter;
- protected JkMain jkMain=null;
-
- /** Set a property. Name is a "component.property". JMX should
- * be used instead.
- */
- public void setProperty( String name, String value ) {
- if( log.isTraceEnabled())
- log.trace("setProperty " + name + " " + value );
- getJkMain().setProperty( name, value );
- properties.put( name, value );
- }
-
- public String getProperty( String name ) {
- return properties.getProperty(name) ;
- }
-
- public Iterator getAttributeNames() {
- return properties.keySet().iterator();
- }
-
- /** Pass config info
- */
- public void setAttribute( String name, Object value ) {
- if( log.isDebugEnabled())
- log.debug("setAttribute " + name + " " + value );
- if( value instanceof String )
- this.setProperty( name, (String)value );
- }
-
- /**
- * Retrieve config info.
- * Primarily for use with the admin webapp.
- */
- public Object getAttribute( String name ) {
- return getJkMain().getProperty(name);
- }
-
- /** The adapter, used to call the connector
- */
- public void setAdapter(Adapter adapter) {
- this.adapter=adapter;
- }
-
- public Adapter getAdapter() {
- return adapter;
- }
-
- public JkMain getJkMain() {
- if( jkMain == null ) {
- jkMain=new JkMain();
- jkMain.setWorkerEnv(wEnv);
-
- }
- return jkMain;
- }
-
- boolean started=false;
-
- /** Start the protocol
- */
- public void init() {
- if( started ) return;
-
- started=true;
-
- if( wEnv==null ) {
- // we are probably not registered - not very good.
- wEnv=getJkMain().getWorkerEnv();
- wEnv.addHandler("container", this );
- }
-
- try {
- // jkMain.setJkHome() XXX;
-
- getJkMain().init();
-
- } catch( Exception ex ) {
- log.error("Error during init",ex);
- }
- }
-
- public void start() {
- try {
- if( oname != null && getJkMain().getDomain() == null) {
- try {
- ObjectName jkmainOname =
- new ObjectName(oname.getDomain() + ":type=JkMain");
- Registry.getRegistry(null, null)
- .registerComponent(getJkMain(), jkmainOname, "JkMain");
- } catch (Exception e) {
- log.error( "Error registering jkmain " + e );
- }
- }
- getJkMain().start();
- } catch( Exception ex ) {
- log.error("Error during startup",ex);
- }
- }
-
- public void pause() throws Exception {
- if(!paused) {
- paused = true;
- getJkMain().pause();
- }
- }
-
- public void resume() throws Exception {
- if(paused) {
- paused = false;
- getJkMain().resume();
- }
- }
-
- public void destroy() {
- if( !started ) return;
-
- started = false;
- getJkMain().stop();
- }
-
-
- // -------------------- Jk handler implementation --------------------
- // Jk Handler mehod
- public int invoke( Msg msg, MsgContext ep )
- throws IOException {
- if( ep.isLogTimeEnabled() )
- ep.setLong( MsgContext.TIMER_PRE_REQUEST, System.currentTimeMillis());
-
- Request req=ep.getRequest();
- Response res=req.getResponse();
-
- if( log.isDebugEnabled() )
- log.debug( "Invoke " + req + " " + res + " " + req.requestURI().toString());
-
- res.setNote( epNote, ep );
- ep.setStatus( MsgContext.JK_STATUS_HEAD );
- RequestInfo rp = req.getRequestProcessor();
- rp.setStage(Constants.STAGE_SERVICE);
- try {
- adapter.service( req, res );
- } catch( Exception ex ) {
- log.info("Error servicing request " + req,ex);
- }
- if(ep.getStatus() != MsgContext.JK_STATUS_CLOSED) {
- res.finish();
- }
-
- req.updateCounters();
- req.recycle();
- res.recycle();
- ep.recycle();
- if( ep.getStatus() == MsgContext.JK_STATUS_ERROR ) {
- return ERROR;
- }
- ep.setStatus( MsgContext.JK_STATUS_NEW );
- rp.setStage(Constants.STAGE_KEEPALIVE);
- return OK;
- }
-
-
- public ObjectName preRegister(MBeanServer server,
- ObjectName oname) throws Exception
- {
- // override - we must be registered as "container"
- this.name="container";
- return super.preRegister(server, oname);
- }
-}
+++ /dev/null
-/*
- * 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.jk.server;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.Properties;
-import java.util.StringTokenizer;
-import java.util.Vector;
-
-import javax.management.MBeanRegistration;
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
-import org.apache.jk.core.JkHandler;
-import org.apache.jk.core.WorkerEnv;
-import org.apache.tomcat.util.IntrospectionUtils;
-import org.apache.tomcat.util.modeler.Registry;
-
-/** Main class used to startup and configure jk. It manages the conf/jk2.properties file
- * and is the target of JMX proxy.
- *
- * It implements a policy of save-on-change - whenever a property is changed at
- * runtime the jk2.properties file will be overriden.
- *
- * You can edit the config file when tomcat is stoped ( or if you don't use JMX or
- * other admin tools ).
- *
- * The format of jk2.properties:
- * <dl>
- * <dt>TYPE[.LOCALNAME].PROPERTY_NAME=VALUE
- * <dd>Set a property on the associated component. TYPE will be used to
- * find the class name and instantiate the component. LOCALNAME allows
- * multiple instances. In JMX mode, TYPE and LOCALNAME will form the
- * JMX name ( eventually combined with a 'jk2' component )
- *
- * <dt>NAME=VALUE
- * <dd>Define global properties to be used in ${} substitutions
- *
- * <dt>class.COMPONENT_TYPE=JAVA_CLASS_NAME
- * <dd>Adds a new 'type' of component. We predefine all known types.
- * </dl>
- *
- * Instances are created the first time a component name is found. In addition,
- * 'handler.list' property will override the list of 'default' components that are
- * loaded automatically.
- *
- * Note that the properties file is just one (simplistic) way to configure jk. We hope
- * to see configs based on registry, LDAP, db, etc. ( XML is not necesarily better )
- *
- * @author Costin Manolache
- */
-public class JkMain implements MBeanRegistration
-{
- WorkerEnv wEnv;
- String propFile;
- Properties props=new Properties();
-
- Properties modules=new Properties();
- boolean modified=false;
- boolean started=false;
- boolean saveProperties=false;
-
- public JkMain()
- {
- JkMain.jkMain=this;
- modules.put("channelSocket", "org.apache.jk.common.ChannelSocket");
- modules.put("channelNioSocket", "org.apache.jk.common.ChannelNioSocket");
- modules.put("channelUnix", "org.apache.jk.common.ChannelUn");
- modules.put("channelJni", "org.apache.jk.common.ChannelJni");
- modules.put("apr", "org.apache.jk.apr.AprImpl");
- modules.put("mx", "org.apache.jk.common.JkMX");
- modules.put("modeler", "org.apache.jk.common.JkModeler");
- modules.put("shm", "org.apache.jk.common.Shm");
- modules.put("request","org.apache.jk.common.HandlerRequest");
- modules.put("container","org.apache.jk.common.HandlerRequest");
- modules.put("modjk","org.apache.jk.common.ModJkMX");
-
- }
-
- public static JkMain getJkMain() {
- return jkMain;
- }
-
- private static String DEFAULT_HTTPS="com.sun.net.ssl.internal.www.protocol";
- private void initHTTPSUrls() {
- try {
- // 11657: if only ajp is used, https: redirects need to work ( at least for 1.3+)
- String value = System.getProperty("java.protocol.handler.pkgs");
- if (value == null) {
- value = DEFAULT_HTTPS;
- } else if (value.indexOf(DEFAULT_HTTPS) >= 0 ) {
- return; // already set
- } else {
- value += "|" + DEFAULT_HTTPS;
- }
- System.setProperty("java.protocol.handler.pkgs", value);
- } catch(Exception ex ) {
- log.info("Error adding SSL Protocol Handler",ex);
- }
- }
-
- // -------------------- Setting --------------------
-
- /** Load a .properties file into and set the values
- * into jk2 configuration.
- */
- public void setPropertiesFile( String p ) {
- propFile=p;
- if( started ) {
- loadPropertiesFile();
- }
- }
-
- public String getPropertiesFile() {
- return propFile;
- }
-
- public void setSaveProperties( boolean b ) {
- saveProperties=b;
- }
-
- /** Set a name/value as a jk2 property
- */
- public void setProperty( String n, String v ) {
- if( "jkHome".equals( n ) ) {
- setJkHome( v );
- }
- if( "propertiesFile".equals( n ) ) {
- setPropertiesFile( v );
- }
- props.put( n, v );
- if( started ) {
- processProperty( n, v );
- saveProperties();
- }
- }
- /**
- * Retrieve a property.
- */
- public Object getProperty(String name) {
- String alias = replacements.get(name);
- Object result = null;
- if(alias != null) {
- result = props.get(alias);
- }
- if(result == null) {
- result = props.get(name);
- }
- return result;
- }
- /**
- * Set the <code>channelClassName</code> that will used to connect to
- * httpd.
- */
- public void setChannelClassName(String name) {
- props.put( "handler.channel.className",name);
- }
-
- public String getChannelClassName() {
- return (String)props.get( "handler.channel.className");
- }
-
- /**
- * Set the <code>workerClassName</code> that will handle the request.
- * ( sort of 'pivot' in axis :-)
- */
- public void setWorkerClassName(String name) {
- props.put( "handler.container.className",name);
- }
-
- public String getWorkerClassName() {
- return (String)props.get( "handler.container.className");
- }
-
- /** Set the base dir of jk2. ( including WEB-INF if in a webapp ).
- * We'll try to guess it from classpath if none is set ( for
- * example on command line ), but if in a servlet environment
- * you need to use Context.getRealPath or a system property or
- * set it expliciltey.
- */
- public void setJkHome( String s ) {
- getWorkerEnv().setJkHome(s);
- }
-
- public String getJkHome() {
- return getWorkerEnv().getJkHome();
- }
-
- String out;
- String err;
- File propsF;
-
- public void setOut( String s ) {
- this.out=s;
- }
-
- public String getOut() {
- return this.out;
- }
-
- public void setErr( String s ) {
- this.err=s;
- }
-
- public String getErr() {
- return this.err;
- }
-
- // -------------------- Initialization --------------------
-
- public void init() throws IOException
- {
- long t1=System.currentTimeMillis();
- if(null != out) {
- PrintStream outS=new PrintStream(new FileOutputStream(out));
- System.setOut(outS);
- }
- if(null != err) {
- PrintStream errS=new PrintStream(new FileOutputStream(err));
- System.setErr(errS);
- }
-
- String home=getWorkerEnv().getJkHome();
- if( home==null ) {
- // XXX use IntrospectionUtil to find myself
- this.guessHome();
- }
- home=getWorkerEnv().getJkHome();
- if( home==null ) {
- log.info( "Can't find home, jk2.properties not loaded");
- }
- if(log.isDebugEnabled())
- log.debug("Starting Jk2, base dir= " + home );
- loadPropertiesFile();
-
- String initHTTPS = (String)props.get("class.initHTTPS");
- if("true".equalsIgnoreCase(initHTTPS)) {
- initHTTPSUrls();
- }
-
- long t2=System.currentTimeMillis();
- initTime=t2-t1;
- }
-
- static String defaultHandlers[]= { "request",
- "container",
- "channelSocket"};
- /*
- static String defaultHandlers[]= { "apr",
- "shm",
- "request",
- "container",
- "channelSocket",
- "channelJni",
- "channelUnix"};
- */
-
- public void stop()
- {
- for( int i=0; i<wEnv.getHandlerCount(); i++ ) {
- if( wEnv.getHandler(i) != null ) {
- try {
- wEnv.getHandler(i).destroy();
- } catch( IOException ex) {
- log.error("Error stopping " + wEnv.getHandler(i).getName(), ex);
- }
- }
- }
-
- started=false;
- }
-
- public void start() throws IOException
- {
- long t1=System.currentTimeMillis();
- // We must have at least 3 handlers:
- // channel is the 'transport'
- // request is the request processor or 'global' chain
- // container is the 'provider'
- // Additional handlers may exist and be used internally
- // or be chained to create one of the standard handlers
-
- String handlers[]=defaultHandlers;
- // backward compat
- String workers=props.getProperty( "handler.list", null );
- if( workers!=null ) {
- handlers= split( workers, ",");
- }
-
- // Load additional component declarations
- processModules();
-
- for( int i=0; i<handlers.length; i++ ) {
- String name= handlers[i];
- JkHandler w=getWorkerEnv().getHandler( name );
- if( w==null ) {
- newHandler( name, "", name );
- }
- }
-
- // Process properties - and add aditional handlers.
- processProperties();
-
- for( int i=0; i<wEnv.getHandlerCount(); i++ ) {
- if( wEnv.getHandler(i) != null ) {
- try {
- wEnv.getHandler(i).init();
- } catch( IOException ex) {
- if( "apr".equals(wEnv.getHandler(i).getName() )) {
- log.info( "APR not loaded, disabling jni components: " + ex.toString());
- } else {
- log.error( "error initializing " + wEnv.getHandler(i).getName(), ex );
- }
- }
- }
- }
-
- started=true;
- long t2=System.currentTimeMillis();
- startTime=t2-t1;
-
- this.saveProperties();
- log.info("Jk running ID=" + wEnv.getLocalId() + " time=" + initTime + "/" + startTime +
- " config=" + propFile);
- }
-
- // -------------------- Usefull methods --------------------
-
- public WorkerEnv getWorkerEnv() {
- if( wEnv==null ) {
- wEnv=new WorkerEnv();
- }
- return wEnv;
- }
-
- public void setWorkerEnv(WorkerEnv wEnv) {
- this.wEnv = wEnv;
- }
-
- /* A bit of magic to support workers.properties without giving
- up the clean get/set
- */
- public void setBeanProperty( Object target, String name, String val ) {
- if( val!=null )
- val=IntrospectionUtils.replaceProperties( val, props, null );
- if( log.isDebugEnabled())
- log.debug( "setProperty " + target + " " + name + "=" + val );
-
- IntrospectionUtils.setProperty( target, name, val );
- }
-
- /*
- * Set a handler property
- */
- public void setPropertyString( String handlerN, String name, String val ) {
- if( log.isDebugEnabled() )
- log.debug( "setProperty " + handlerN + " " + name + "=" + val );
- Object target=getWorkerEnv().getHandler( handlerN );
-
- setBeanProperty( target, name, val );
- if( started ) {
- saveProperties();
- }
-
- }
-
- /** The time it took to initialize jk ( ms)
- */
- public long getInitTime() {
- return initTime;
- }
-
- /** The time it took to start jk ( ms )
- */
- public long getStartTime() {
- return startTime;
- }
-
- // -------------------- Main --------------------
-
- long initTime;
- long startTime;
- static JkMain jkMain=null;
-
- public static void main(String args[]) {
- try {
- if( args.length == 1 &&
- ( "-?".equals(args[0]) || "-h".equals( args[0])) ) {
- System.out.println("Usage: ");
- System.out.println(" JkMain [args]");
- System.out.println();
- System.out.println(" Each bean setter corresponds to an arg ( like -debug 10 )");
- System.out.println(" System properties:");
- System.out.println(" jk2.home Base dir of jk2");
- return;
- }
-
- jkMain=new JkMain();
-
- IntrospectionUtils.processArgs( jkMain, args, new String[] {},
- null, new Hashtable<Object,Object>());
-
- jkMain.init();
- jkMain.start();
- } catch( Exception ex ) {
- log.warn("Error running",ex);
- }
- }
-
- // -------------------- Private methods --------------------
-
-
- private boolean checkPropertiesFile() {
- if(propFile == null) {
- return false;
- }
- propsF = new File(propFile);
- if(!propsF.isAbsolute()) {
- String home = getWorkerEnv().getJkHome();
- if( home == null ) {
- return false;
- }
- propsF = new File(home, propFile);
- }
- return propsF.exists();
- }
-
- private void loadPropertiesFile() {
- if(!checkPropertiesFile()) {
- return;
- }
-
- try {
- props.load( new FileInputStream(propsF) );
- } catch(IOException ex ){
- log.warn("Unable to load properties from "+propsF,ex);
- }
- }
-
- public void saveProperties() {
- if( !saveProperties) return;
-
- if(propsF == null) {
- log.warn("No properties file specified. Unable to save");
- return;
- }
- // Temp - to check if it works
- File outFile= new File(propsF.getParentFile(), propsF.getName()+".save");
- log.debug("Saving properties " + outFile );
- try {
- props.store( new FileOutputStream(outFile), "AUTOMATICALLY GENERATED" );
- } catch(IOException ex ){
- log.warn("Unable to save to "+outFile,ex);
- }
- }
-
- // translate top-level keys ( from coyote or generic ) into component keys
- static Hashtable<String,String> replacements =
- new Hashtable<String,String>();
- static {
- replacements.put("port","channelSocket.port");
- replacements.put("maxThreads", "channelSocket.maxThreads");
- replacements.put("minSpareThreads", "channelSocket.minSpareThreads");
- replacements.put("maxSpareThreads", "channelSocket.maxSpareThreads");
- replacements.put("backlog", "channelSocket.backlog");
- replacements.put("tcpNoDelay", "channelSocket.tcpNoDelay");
- replacements.put("soTimeout", "channelSocket.soTimeout");
- replacements.put("timeout", "channelSocket.timeout");
- replacements.put("address", "channelSocket.address");
- replacements.put("bufferSize", "channelSocket.bufferSize");
- replacements.put("tomcatAuthentication", "request.tomcatAuthentication");
- replacements.put("packetSize", "channelSocket.packetSize");
- }
-
- private void preProcessProperties() {
- // TODO This can be fixed in Java 6
- Enumeration<String> keys = (Enumeration) props.keys();
- Vector<String> v=new Vector<String>();
-
- while( keys.hasMoreElements() ) {
- String key=keys.nextElement();
- Object newName=replacements.get(key);
- if( newName !=null ) {
- v.addElement(key);
- }
- }
- keys=v.elements();
- while( keys.hasMoreElements() ) {
- String key = keys.nextElement();
- Object propValue = props.getProperty( key );
- String replacement = replacements.get(key);
- props.put(replacement, propValue);
- if( log.isDebugEnabled())
- log.debug("Substituting " + key + " " + replacement + " " +
- propValue);
- }
- }
-
- private void processProperties() {
- preProcessProperties();
- Enumeration<String> keys = (Enumeration) props.keys();
-
- while( keys.hasMoreElements() ) {
- String name= keys.nextElement();
- String propValue=props.getProperty( name );
-
- processProperty( name, propValue );
- }
- }
-
- private void processProperty(String name, String propValue) {
- String type=name;
- String fullName=name;
- String localName="";
- String propName="";
- // ignore
- if( name.startsWith("key.")) return;
-
- int dot=name.indexOf(".");
- int lastDot=name.lastIndexOf(".");
- if( dot > 0 ) {
- type=name.substring(0, dot );
- if( dot != lastDot ) {
- localName=name.substring( dot + 1, lastDot );
- fullName=type + "." + localName;
- } else {
- fullName=type;
- }
- propName=name.substring( lastDot+1);
- } else {
- return;
- }
-
- if( log.isDebugEnabled() )
- log.debug( "Processing " + type + ":" + localName + ":" + fullName + " " + propName );
- if( "class".equals( type ) || "handler".equals( type ) ) {
- return;
- }
-
- JkHandler comp=getWorkerEnv().getHandler( fullName );
- if( comp==null ) {
- comp=newHandler( type, localName, fullName );
- }
- if( comp==null )
- return;
-
- if( log.isDebugEnabled() )
- log.debug("Setting " + propName + " on " + fullName + " " + comp);
- this.setBeanProperty( comp, propName, propValue );
- }
-
- private JkHandler newHandler( String type, String localName, String fullName )
- {
- JkHandler handler;
- String classN=modules.getProperty(type);
- if( classN == null ) {
- log.error("No class name for " + fullName + " " + type );
- return null;
- }
- try {
- Class<?> channelclass = Class.forName(classN);
- handler=(JkHandler)channelclass.newInstance();
- } catch (Throwable ex) {
- handler=null;
- log.error( "Can't create " + fullName, ex );
- return null;
- }
- if( this.domain != null ) {
- try {
- ObjectName handlerOname = new ObjectName
- (this.domain + ":" + "type=JkHandler,name=" + fullName);
- Registry.getRegistry(null, null).registerComponent(handler, handlerOname, classN);
- } catch (Exception e) {
- log.error( "Error registering " + fullName, e );
- }
-
- }
- wEnv.addHandler( fullName, handler );
- return handler;
- }
-
- private void processModules() {
- Enumeration<String> keys = (Enumeration)props.keys();
- int plen=6;
-
- while( keys.hasMoreElements() ) {
- String k=keys.nextElement();
- if( ! k.startsWith( "class." ) )
- continue;
-
- String name= k.substring( plen );
- String propValue=props.getProperty( k );
-
- if( log.isDebugEnabled()) log.debug("Register " + name + " " + propValue );
- modules.put( name, propValue );
- }
- }
-
- private String[] split(String s, String delim ) {
- Vector<String> v = new Vector<String>();
- StringTokenizer st=new StringTokenizer(s, delim );
- while( st.hasMoreTokens() ) {
- v.addElement( st.nextToken());
- }
- String res[]=new String[ v.size() ];
- for( int i=0; i<res.length; i++ ) {
- res[i]=v.elementAt(i);
- }
- return res;
- }
-
- // guessing home
- private static String CNAME="org/apache/jk/server/JkMain.class";
-
- private void guessHome() {
- String home= wEnv.getJkHome();
- if( home != null )
- return;
- home=IntrospectionUtils.guessInstall( "jk2.home","jk2.home",
- "tomcat-jk2.jar", CNAME );
- if( home != null ) {
- log.info("Guessed home " + home );
- wEnv.setJkHome( home );
- }
- }
-
- static org.apache.juli.logging.Log log=
- org.apache.juli.logging.LogFactory.getLog( JkMain.class );
-
- 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() {
- }
-
- public void pause() throws Exception {
- // wEnv sometime null at shutdown - bug45591
- if (wEnv != null) {
- for( int i=0; i<wEnv.getHandlerCount(); i++ ) {
- if( wEnv.getHandler(i) != null ) {
- wEnv.getHandler(i).pause();
- }
- }
- }
- }
-
- public void resume() throws Exception {
- for( int i=0; i<wEnv.getHandlerCount(); i++ ) {
- if( wEnv.getHandler(i) != null ) {
- wEnv.getHandler(i).resume();
- }
- }
- }
-
-
-}