From: markt Date: Thu, 9 Apr 2009 10:27:01 +0000 (+0000) Subject: Remove the org.apache.jk package as per discussion on dev list. Do this early in... X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=bd2889cf6fbe5b48634391da0de86c0ba0f1b1d4;p=tomcat7.0 Remove the org.apache.jk package as per discussion on dev list. Do this early in Tomcat 7 development to increase chances of identifying any issues with org.apache.coyoye.ajp package git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@763588 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/java/org/apache/jk/common/AjpConstants.java b/java/org/apache/jk/common/AjpConstants.java deleted file mode 100644 index df16b9021..000000000 --- a/java/org/apache/jk/common/AjpConstants.java +++ /dev/null @@ -1,198 +0,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. - */ - -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; - -} diff --git a/java/org/apache/jk/common/ChannelNioSocket.java b/java/org/apache/jk/common/ChannelNioSocket.java deleted file mode 100644 index 3f2205efd..000000000 --- a/java/org/apache/jk/common/ChannelNioSocket.java +++ /dev/null @@ -1,1201 +0,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. - */ - -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. - * - *

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 true 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 sels = selector.selectedKeys(); - Iterator 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; - } - } - -} - diff --git a/java/org/apache/jk/common/ChannelSocket.java b/java/org/apache/jk/common/ChannelSocket.java deleted file mode 100644 index 3d38e9d1a..000000000 --- a/java/org/apache/jk/common/ChannelSocket.java +++ /dev/null @@ -1,897 +0,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. - */ - -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. - * - *

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 true 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; - } - } - -} - diff --git a/java/org/apache/jk/common/HandlerDispatch.java b/java/org/apache/jk/common/HandlerDispatch.java deleted file mode 100644 index 52538caf6..000000000 --- a/java/org/apache/jk/common/HandlerDispatch.java +++ /dev/null @@ -1,101 +0,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. - */ - -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 ); - } - - } diff --git a/java/org/apache/jk/common/HandlerRequest.java b/java/org/apache/jk/common/HandlerRequest.java deleted file mode 100644 index b489707c7..000000000 --- a/java/org/apache/jk/common/HandlerRequest.java +++ /dev/null @@ -1,690 +0,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. - */ - -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); - - } - - } - -} diff --git a/java/org/apache/jk/common/JkInputStream.java b/java/org/apache/jk/common/JkInputStream.java deleted file mode 100644 index 7c58ddca6..000000000 --- a/java/org/apache/jk/common/JkInputStream.java +++ /dev/null @@ -1,341 +0,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. - */ - -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 - * 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 ); - - -} - diff --git a/java/org/apache/jk/common/MsgAjp.java b/java/org/apache/jk/common/MsgAjp.java deleted file mode 100644 index db5df5541..000000000 --- a/java/org/apache/jk/common/MsgAjp.java +++ /dev/null @@ -1,354 +0,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. - */ - -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 not 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 not 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 ); - } - -} diff --git a/java/org/apache/jk/common/WorkerDummy.java b/java/org/apache/jk/common/WorkerDummy.java deleted file mode 100644 index 376785070..000000000 --- a/java/org/apache/jk/common/WorkerDummy.java +++ /dev/null @@ -1,91 +0,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. - */ - -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; -} - diff --git a/java/org/apache/jk/config/ApacheConfig.java b/java/org/apache/jk/config/ApacheConfig.java deleted file mode 100644 index 71755e830..000000000 --- a/java/org/apache/jk/config/ApacheConfig.java +++ /dev/null @@ -1,556 +0,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. - */ - -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. -

- This config interceptor is enabled by inserting an ApacheConfig - Listener in - the server.xml file like so: -

-    * < Server ... >
-    *   ...
-    *   org.apache.ajp.tomcat4.config.ApacheConfig 
-    *       options />
-    *   ...
-    * < /Server >
-    
- where options can include any of the following attributes: - -

- @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 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. -

- @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 " ); - } - - // Verify the file exists !! - mod_jk.println(""); - mod_jk.println(" LoadModule jk_module \""+ - modJk.toString().replace('\\','/') + - "\""); - mod_jk.println(""); - 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 " ); - 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(""); - 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(""); - 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"); - 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 + ""); - 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 + ""); - mod_jk.println(indent + " AllowOverride None"); - mod_jk.println(indent + " deny from all"); - mod_jk.println(indent + ""); - // Deny serving any files from META-INF - mod_jk.println(); - mod_jk.println(indent + ""); - mod_jk.println(indent + " AllowOverride None"); - mod_jk.println(indent + " deny from all"); - mod_jk.println(indent + ""); - 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 + - ""); - mod_jk.println(indent + " AllowOverride None"); - mod_jk.println(indent + " deny from all"); - mod_jk.println(indent + ""); - mod_jk.println(); - mod_jk.println(indent + - ""); - mod_jk.println(indent + " AllowOverride None"); - mod_jk.println(indent + " deny from all"); - mod_jk.println(indent + ""); - } - 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; - } - -} diff --git a/java/org/apache/jk/config/BaseJkConfig.java b/java/org/apache/jk/config/BaseJkConfig.java deleted file mode 100644 index 661c01ca3..000000000 --- a/java/org/apache/jk/config/BaseJkConfig.java +++ /dev/null @@ -1,516 +0,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. - */ - -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. -

- This config interceptor is enabled by inserting a Config - element in the <ContextManager> tag body inside - the server.xml file like so: -

-    * < ContextManager ... >
-    *   ...
-    *   <???Config options />
-    *   ...
-    * < /ContextManager >
-    
- where options can include any of the following attributes: - -

- @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 true 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".

- *

- * However, if the path is set to an absolute path, - * this attribute is ignored. - *

- * 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; - } -} diff --git a/java/org/apache/jk/config/GeneratorApache2.java b/java/org/apache/jk/config/GeneratorApache2.java deleted file mode 100644 index fe833f25b..000000000 --- a/java/org/apache/jk/config/GeneratorApache2.java +++ /dev/null @@ -1,195 +0,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. - */ - -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(""); - 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(""); - out.println(); - - out.println(""); - out.println(" AllowOverride None"); - out.println(" Deny from all"); - out.println(""); - out.println(); - out.println(""); - out.println(" AllowOverride None"); - out.println(" Deny from all"); - out.println(""); - out.println(); - } - - private void generateWelcomeFiles( PrintWriter out ) { - Vector wf= wxml.getWellcomeFiles(); - out.print(" DirectoryIndex "); - for( int i=0; i"); - 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( ""); - out.println(); - } - - public void generateFilterMapping( String servlet, String url ) { - out.println( ""); - 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( ""); - out.println(); - } - - public void generateLoginConfig( String loginPage, - String errPage, String authM ) { - out.println( ""); - out.println( " SetHandler jakarta-servlet2" ); - out.println( " JkUriSet group " + worker ); - out.println( " JkUriSet host " + vhost ); - out.println( " JkUriSet context " + cpath ); - out.println( ""); - out.println(); - } - - public void generateErrorPage( int err, String location ) { - - } - - // XXX Only if BASIC/DIGEST and 'integrated auth' - public void generateConstraints( Vector urls, Vector methods, - Vector roles, boolean isSSL ) { - for( int i=0; i"); - - if( methods.size() > 0 ) { - out.print(" " ); - } - - out.println( " AuthType basic" ); - out.print( " Require group " ); - for( int j=0; j 0 ) { - out.println(" "); - } - - out.println( ""); - } - } -} diff --git a/java/org/apache/jk/config/GeneratorJk1.java b/java/org/apache/jk/config/GeneratorJk1.java deleted file mode 100644 index 96bb9eb88..000000000 --- a/java/org/apache/jk/config/GeneratorJk1.java +++ /dev/null @@ -1,114 +0,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. - */ - -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 wf ) { - - } - - - public void generateConstraints( Vector urls, Vector methods, - Vector roles, boolean isSSL ) { - for( int i=0; i - This config interceptor is enabled by inserting an IISConfig - element in the <ContextManager> tag body inside - the server.xml file like so: -

-    * < ContextManager ... >
-    *   ...
-    *   <IISConfig options />
-    *   ...
-    * < /ContextManager >
-    
- where options can include any of the following attributes: - -

- @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. -

- @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(); - } - -} diff --git a/java/org/apache/jk/config/NSConfig.java b/java/org/apache/jk/config/NSConfig.java deleted file mode 100644 index f1203efe6..000000000 --- a/java/org/apache/jk/config/NSConfig.java +++ /dev/null @@ -1,328 +0,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. - */ - -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. -

- This config interceptor is enabled by inserting an NSConfig - element in the <ContextManager> tag body inside - the server.xml file like so: -

-    * < ContextManager ... >
-    *   ...
-    *   <NSConfig options />
-    *   ...
-    * < /ContextManager >
-    
- where options can include any of the following attributes: - -

- @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. -

- @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(""); - 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=\"\""); - 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(""); - objfile.println(); - - objfile.println("#######################################################"); - objfile.println("# New object to execute your servlet requests."); - objfile.println("#######################################################"); - objfile.println(""); - objfile.println("ObjectType fn=force-type type=text/html"); - objfile.println("Service fn=\"jk_service\" worker=\""+ jkWorker + "\" path=\"/*\""); - objfile.println(""); - 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(""); - - objfile.println("NameTrans fn=\"assign-name\" from=\"" + ctxPath + "\" name=\"" + objectName + "\""); - objfile.println("NameTrans fn=\"assign-name\" from=\"" + ctxPath + "/*\" name=\"" + objectName + "\""); - objfile.println(""); - } - - - // -------------------- 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(""); - // 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(""); - } - - /** 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; - } - -} diff --git a/java/org/apache/jk/config/WebXml2Jk.java b/java/org/apache/jk/config/WebXml2Jk.java deleted file mode 100644 index 1ec5ee990..000000000 --- a/java/org/apache/jk/config/WebXml2Jk.java +++ /dev/null @@ -1,453 +0,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. - */ - -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 urls, Vector methods, - Vector 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 getWellcomeFiles() { - Node n0=getChild( webN, "welcome-file-list" ); - Vector wF = new Vector(); - 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 methods = new Vector(); - Vector urls= new Vector(); - Vector roles= new Vector(); - 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()); - 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; - } - -} diff --git a/java/org/apache/jk/core/JkChannel.java b/java/org/apache/jk/core/JkChannel.java deleted file mode 100644 index 76cb9301f..000000000 --- a/java/org/apache/jk/core/JkChannel.java +++ /dev/null @@ -1,77 +0,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. - */ - -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(); - -} diff --git a/java/org/apache/jk/core/JkHandler.java b/java/org/apache/jk/core/JkHandler.java deleted file mode 100644 index cdbe7e91c..000000000 --- a/java/org/apache/jk/core/JkHandler.java +++ /dev/null @@ -1,201 +0,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. - */ - -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 { - } - -} diff --git a/java/org/apache/jk/core/Msg.java b/java/org/apache/jk/core/Msg.java deleted file mode 100644 index da66ba772..000000000 --- a/java/org/apache/jk/core/Msg.java +++ /dev/null @@ -1,154 +0,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. - */ - -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 not 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 ); - } - - -} diff --git a/java/org/apache/jk/core/MsgContext.java b/java/org/apache/jk/core/MsgContext.java deleted file mode 100644 index bdbf1439d..000000000 --- a/java/org/apache/jk/core/MsgContext.java +++ /dev/null @@ -1,402 +0,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. - */ - -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(); - } -} diff --git a/java/org/apache/jk/core/WorkerEnv.java b/java/org/apache/jk/core/WorkerEnv.java deleted file mode 100644 index c6d19b10a..000000000 --- a/java/org/apache/jk/core/WorkerEnv.java +++ /dev/null @@ -1,146 +0,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. - */ - -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 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 handlersMap = - new Hashtable(); - 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 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 - - - - - - -

Jk2 interfaces

-

Core interfaces for jk2, similar with the interfaces defined in the C -side ( jk2/include ).
-

-

The implementations are in common/ and server/.
-

-


-

- - diff --git a/java/org/apache/jk/mbeans-descriptors.xml b/java/org/apache/jk/mbeans-descriptors.xml deleted file mode 100644 index 10a66c09d..000000000 --- a/java/org/apache/jk/mbeans-descriptors.xml +++ /dev/null @@ -1,557 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/java/org/apache/jk/server/JkCoyoteHandler.java b/java/org/apache/jk/server/JkCoyoteHandler.java deleted file mode 100644 index c5c7d9cae..000000000 --- a/java/org/apache/jk/server/JkCoyoteHandler.java +++ /dev/null @@ -1,218 +0,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. - */ - -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); - } -} diff --git a/java/org/apache/jk/server/JkMain.java b/java/org/apache/jk/server/JkMain.java deleted file mode 100644 index 0bca8e4d5..000000000 --- a/java/org/apache/jk/server/JkMain.java +++ /dev/null @@ -1,700 +0,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. - */ - -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: - *
- *
TYPE[.LOCALNAME].PROPERTY_NAME=VALUE - *
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 ) - * - *
NAME=VALUE - *
Define global properties to be used in ${} substitutions - * - *
class.COMPONENT_TYPE=JAVA_CLASS_NAME - *
Adds a new 'type' of component. We predefine all known types. - *
- * - * 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 channelClassName 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 workerClassName 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()); - - 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 replacements = - new Hashtable(); - 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 keys = (Enumeration) props.keys(); - Vector v=new Vector(); - - 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 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 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 v = new Vector(); - StringTokenizer st=new StringTokenizer(s, delim ); - while( st.hasMoreTokens() ) { - v.addElement( st.nextToken()); - } - String res[]=new String[ v.size() ]; - for( int i=0; i