tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cos...@apache.org
Subject svn commit: r534293 [8/11] - in /tomcat/sandbox/tomcat-lite: ./ bin/ external/ java/ java/org/apache/commons/logging/ java/org/apache/tomcat/lite/ java/org/apache/tomcat/lite/ctxmap/ java/org/apache/tomcat/lite/http/ java/org/apache/tomcat/lite/http11/...
Date Wed, 02 May 2007 02:22:50 GMT
Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/jsp/SingleThreadedProxyServlet.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/jsp/SingleThreadedProxyServlet.java?view=auto&rev=534293
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/jsp/SingleThreadedProxyServlet.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/jsp/SingleThreadedProxyServlet.java Tue May  1 19:22:45 2007
@@ -0,0 +1,62 @@
+/*
+ */
+package org.apache.tomcat.servlets.jsp;
+
+import java.util.Stack;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/** For SingleThreadedServlet support. 
+ * 
+ * This is container independent.
+ * 
+ * Will maintain a pool of servlets, etc 
+ * 
+ * 
+ * @author Costin Manolache
+ */
+public class SingleThreadedProxyServlet extends HttpServlet {
+
+    private Class classClass = null;
+    private transient boolean singleThreadModel = false;
+    /**
+     * Stack containing the STM instances.
+     */
+    private transient Stack instancePool = null;
+
+    /**
+     * Extra params: 
+     *   - servlet-class - the class of the single-threaded servlet
+     *   - 
+     * 
+     */
+    public void init() {
+        
+    }
+    
+    public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException {
+        synchronized (instancePool) {
+            if (instancePool.isEmpty()) {
+                try {
+                    Servlet newServlet = null; // loadServlet();
+
+                    // todo: should we init each of them ?
+                    
+                    newServlet.service(req, res);
+                    
+                    
+                } catch (Throwable e) {
+                    throw new ServletException("allocate ",
+                            e);
+                }
+            }
+            Servlet s = (Servlet) instancePool.pop();
+        }
+
+        
+    }
+}

Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/log/LogFilter.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/log/LogFilter.java?view=auto&rev=534293
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/log/LogFilter.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/log/LogFilter.java Tue May  1 19:22:45 2007
@@ -0,0 +1,61 @@
+/*
+ */
+package org.apache.tomcat.servlets.log;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * Simple filter to log requests. 
+ * 
+ * Goals: compact representation, low access to the disk, online
+ * access to the logs, etc.
+ * 
+ * LogServlet is used to decode this, either from the internal representation
+ * or from disk.
+ * 
+ * @author Costin Manolache
+ */
+public class LogFilter implements Filter {
+    
+    // don't save logs, expire them.
+    private long expire = 0;
+    
+    // don't keep more than maxRows
+    private int maxRows;
+    private int interval;
+    
+    // if set, logs will be saved to the file when maxRows or interval is met
+    private String file;
+
+    private ServletContext servletContext; 
+    
+    public void init(FilterConfig cfg) throws ServletException {
+        servletContext = cfg.getServletContext();
+        servletContext.log("Log filter " + servletContext.getContextPath());
+    }
+
+    public void doFilter(ServletRequest sreq, ServletResponse sres, 
+                         FilterChain chain) 
+            throws IOException, ServletException {
+        HttpServletRequest req = (HttpServletRequest)sreq;
+        
+        String method = req.getMethod();
+        
+        chain.doFilter(sreq, sres);
+        
+        servletContext.log(method + " " + req.getRequestURI());
+    }
+
+    public void destroy() {
+    }
+
+}

Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/log/LogServlet.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/log/LogServlet.java?view=auto&rev=534293
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/log/LogServlet.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/log/LogServlet.java Tue May  1 19:22:45 2007
@@ -0,0 +1,11 @@
+/*
+ */
+package org.apache.tomcat.servlets.log;
+
+/** Online access to the logs.
+ * 
+ * @author Costin Manolache
+ */
+public class LogServlet {
+
+}

Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/log/RequestInfoFilter.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/log/RequestInfoFilter.java?view=auto&rev=534293
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/log/RequestInfoFilter.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/log/RequestInfoFilter.java Tue May  1 19:22:45 2007
@@ -0,0 +1,86 @@
+/*
+ */
+package org.apache.tomcat.servlets.log;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.Enumeration;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletRequestWrapper;
+import javax.servlet.ServletResponse;
+import javax.servlet.ServletResponseWrapper;
+
+import org.apache.tomcat.lite.FilterChainImpl;
+import org.apache.tomcat.lite.ServletRequestImpl;
+import org.apache.tomcat.lite.ServletResponseImpl;
+import org.apache.tomcat.util.http.MimeHeaders;
+
+public class RequestInfoFilter implements Filter {
+
+    public void init(FilterConfig filterConfig) throws ServletException {
+    }
+
+    public void doFilter(ServletRequest request, 
+                         ServletResponse response, 
+                         FilterChain chain) 
+            throws IOException, ServletException {
+        
+        PrintStream out = System.err;
+        while (request instanceof ServletRequestWrapper) {
+            request = ((ServletRequestWrapper)request).getRequest();
+        }
+        ServletRequestImpl req = (ServletRequestImpl)request;
+        // TODO: cookies, session, headers
+        out.println("Q(" + 
+                req.getMethod() + " H:" + 
+                req.getServerName() + " L:" +
+                req.getContentLength() + " C:" +
+                req.getContextPath() + " S:" + 
+                req.getServletPath() + " P:" +
+                req.getPathInfo() + " Q:" +
+                req.getQueryString() + " " +
+                ")");
+        FilterChainImpl filterChain = req.getFilterChain();
+        for( int i=0; i<filterChain.getSize(); i++) {
+            out.println("F: " +filterChain.getFilter(i).getFilterName());
+        }
+        out.println("S: " + filterChain.getServletConfig().getServletName());
+        
+        Enumeration headerNames = req.getHeaderNames();
+        while (headerNames.hasMoreElements()) {
+            String hn = (String)headerNames.nextElement();
+            Enumeration headers = req.getHeaders(hn);
+            while(headers.hasMoreElements()) {
+                out.println(hn + ": " + headers.nextElement());
+            }
+        }
+        chain.doFilter(request, response);
+        while (response instanceof ServletResponseWrapper) {
+            response = ((ServletResponseWrapper)response).getResponse();
+        }
+        if ( response instanceof ServletResponseImpl) {
+            ServletResponseImpl res = (ServletResponseImpl)response;
+            out.println("R(" + res.getStatus() + " " +
+                    res.getContentLength() + " " + 
+                    res.getContentType() + " " + 
+                    ")");
+//            MimeHeaders headerNames2 = res.getCoyoteResponse().getMimeHeaders();
+//            for( int i = 0; i < headerNames2.size(); i++ ) {
+//                out.println(headerNames2.getName(i) + ": " + 
+//                        headerNames2.getValue(i));
+//            }
+        } else {
+            out.println("R(Unexpected wrapped object)");
+        }
+        out.println();
+    }
+
+    public void destroy() {
+    }
+
+}

Modified: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/sec/DigestAuthServlet.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/sec/DigestAuthServlet.java?view=diff&rev=534293&r1=534292&r2=534293
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/sec/DigestAuthServlet.java (original)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/sec/DigestAuthServlet.java Tue May  1 19:22:45 2007
@@ -47,6 +47,7 @@
 public class DigestAuthServlet extends SimpleAuthServlet {
 
     private static Log log = LogFactory.getLog(DigestAuthServlet.class);
+    private boolean debugDigest;
     
     // -------------------------------------------------------------- Constants
 
@@ -82,17 +83,7 @@
     }
 
     public void init() throws ServletException {
-        //super.init();
-        try {
-            //
-            //if (key == null) key = Long.toString(new Random().nextLong());
-            if (md5Helper == null)
-                md5Helper = MessageDigest.getInstance("MD5");
-            users.put("test", "test");
-        } catch (NoSuchAlgorithmException e) {
-            e.printStackTrace();
-            throw new IllegalStateException();
-        }
+        users.put("test", "test");
     }
 
     // --------------------------------------------------------- Public Methods
@@ -148,8 +139,15 @@
         // ( and we want to validate )
         String opaque = Long.toString(currentTime);
         String nOnce = opaque + ":" + key;
-
         byte[] buffer = null;
+        if (md5Helper == null) {
+          try {
+            md5Helper = MessageDigest.getInstance("MD5");
+          } catch (NoSuchAlgorithmException e) {
+            System.err.println("No md5 " + e);
+            return null;
+          }
+        }
         synchronized (md5Helper) {
             buffer = md5Helper.digest(nOnce.getBytes());
         }
@@ -281,7 +279,7 @@
             serverDigest = md5Encoder.encode(md5Helper.digest(valueBytes));
         }
         
-        if (log.isDebugEnabled()) {
+        if (debugDigest) {
             log.debug("Digest : " + clientDigest + " Username:" + username 
                     + " ClientSigest:" + clientDigest + " nOnce:" + nOnce 
                     + " nc:" + nc + " cnonce:" + cnonce + " qop:" + qop 

Modified: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/session/HttpSessionImpl.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/session/HttpSessionImpl.java?view=diff&rev=534293&r1=534292&r2=534293
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/session/HttpSessionImpl.java (original)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/session/HttpSessionImpl.java Tue May  1 19:22:45 2007
@@ -33,7 +33,7 @@
 import javax.servlet.http.HttpSessionEvent;
 import javax.servlet.http.HttpSessionListener;
 
-import org.apache.tomcat.servlets.util.Enumerator;
+import org.apache.tomcat.lite.Enumerator;
 
 /**
  * Standard implementation of the <b>Session</b> interface.  

Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/session/RandomGenerator.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/session/RandomGenerator.java?view=auto&rev=534293
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/session/RandomGenerator.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/session/RandomGenerator.java Tue May  1 19:22:45 2007
@@ -0,0 +1,352 @@
+package org.apache.tomcat.servlets.session;
+
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Random;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *  Generates random IDs, useable as cookies.
+ * 
+ *  Based on code from tomcat session manager - but general purpose.
+ *  Can use /dev/urandom or similar file.
+ *  
+ * 
+ */
+public class RandomGenerator {
+    protected DataInputStream randomIS=null;
+    protected String devRandomSource="/dev/urandom";
+
+    protected static Log log = LogFactory.getLog(RandomGenerator.class);
+
+    /**
+     * The message digest algorithm to be used when generating session
+     * identifiers.  This must be an algorithm supported by the
+     * <code>java.security.MessageDigest</code> class on your platform.
+     */
+    protected String algorithm = "MD5";
+
+    /**
+     * The session id length of Sessions created by this Manager.
+     */
+    protected int sessionIdLength = 16;
+
+    
+    /**
+     * Return the MessageDigest implementation to be used when
+     * creating session identifiers.
+     */
+    protected MessageDigest digest = null;
+
+    public String jvmRoute;
+
+    /**
+     * A String initialization parameter used to increase the entropy of
+     * the initialization of our random number generator.
+     */
+    protected String entropy = null;
+
+    /**
+     * A random number generator to use when generating session identifiers.
+     */
+    protected Random random = null;
+
+    /**
+     * Return the message digest algorithm for this Manager.
+     */
+    public String getAlgorithm() {
+        return (this.algorithm);
+    }
+    
+    public void init() {
+        // Initialize random number generation
+        getRandomBytes(new byte[16]);
+    }
+
+
+    /**
+     * Set the message digest algorithm for this Manager.
+     *
+     * @param algorithm The new message digest algorithm
+     */
+    public void setAlgorithm(String algorithm) {
+        this.algorithm = algorithm;
+    }
+    
+    /**
+     * Return the MessageDigest object to be used for calculating
+     * session identifiers.  If none has been created yet, initialize
+     * one the first time this method is called.
+     */
+    public synchronized MessageDigest getDigest() {
+
+        if (this.digest == null) {
+            long t1=System.currentTimeMillis();
+            try {
+                this.digest = MessageDigest.getInstance(algorithm);
+            } catch (NoSuchAlgorithmException e) {
+                log.error("Algorithm not found", e);
+                try {
+                    this.digest = MessageDigest.getInstance("MD5");
+                } catch (NoSuchAlgorithmException f) {
+                    log.error("No message digest available", f);
+                    this.digest = null;
+                }
+            }
+            long t2=System.currentTimeMillis();
+            if( log.isDebugEnabled() )
+                log.debug("getDigest() " + (t2-t1));
+        }
+
+        return (this.digest);
+
+    }
+    
+    /**
+     * Generate and return a new session identifier.
+     */
+    public synchronized String generateSessionId() {
+
+        byte random[] = new byte[16];
+        String result = null;
+
+        // Render the result as a String of hexadecimal digits
+        StringBuffer buffer = new StringBuffer();
+        int resultLenBytes = 0;
+
+        while (resultLenBytes < this.sessionIdLength) {
+            getRandomBytes(random);
+            random = getDigest().digest(random);
+            for (int j = 0;
+            j < random.length && resultLenBytes < this.sessionIdLength;
+            j++) {
+                byte b1 = (byte) ((random[j] & 0xf0) >> 4);
+                byte b2 = (byte) (random[j] & 0x0f);
+                if (b1 < 10)
+                    buffer.append((char) ('0' + b1));
+                else
+                    buffer.append((char) ('A' + (b1 - 10)));
+                if (b2 < 10)
+                    buffer.append((char) ('0' + b2));
+                else
+                    buffer.append((char) ('A' + (b2 - 10)));
+                resultLenBytes++;
+            }
+        }
+        if (jvmRoute != null) {
+            buffer.append('.').append(jvmRoute);
+        }
+        result = buffer.toString();
+        return (result);
+
+    }
+    
+    protected void getRandomBytes(byte bytes[]) {
+        // Generate a byte array containing a session identifier
+        if (devRandomSource != null && randomIS == null) {
+            setRandomFile(devRandomSource);
+        }
+        if (randomIS != null) {
+            try {
+                int len = randomIS.read(bytes);
+                if (len == bytes.length) {
+                    return;
+                }
+                if(log.isDebugEnabled())
+                    log.debug("Got " + len + " " + bytes.length );
+            } catch (Exception ex) {
+                // Ignore
+            }
+            devRandomSource = null;
+            
+            try {
+                randomIS.close();
+            } catch (Exception e) {
+                log.warn("Failed to close randomIS.");
+            }
+            
+            randomIS = null;
+        }
+        getRandom().nextBytes(bytes);
+    }
+
+    /**
+     * Return the random number generator instance we should use for
+     * generating session identifiers.  If there is no such generator
+     * currently defined, construct and seed a new one.
+     */
+    public Random getRandom() {
+        if (this.random == null) {
+            // Calculate the new random number generator seed
+            long seed = System.currentTimeMillis();
+            long t1 = seed;
+            char entropy[] = getEntropy().toCharArray();
+            for (int i = 0; i < entropy.length; i++) {
+                long update = ((byte) entropy[i]) << ((i % 8) * 8);
+                seed ^= update;
+            }
+            try {
+                // Construct and seed a new random number generator
+                Class clazz = Class.forName(randomClass);
+                this.random = (Random) clazz.newInstance();
+                this.random.setSeed(seed);
+            } catch (Exception e) {
+                // Fall back to the simple case
+                log.error("Failed to create random " + randomClass, e);
+                this.random = new java.util.Random();
+                this.random.setSeed(seed);
+            }
+            if(log.isDebugEnabled()) {
+                long t2=System.currentTimeMillis();
+                if( (t2-t1) > 100 )
+                    log.debug("Init random: " + " " + (t2-t1));
+            }
+        }
+        
+        return (this.random);
+
+    }
+    
+    /**
+     * Return the entropy increaser value, or compute a semi-useful value
+     * if this String has not yet been set.
+     */
+    public String getEntropy() {
+
+        // Calculate a semi-useful value if this has not been set
+        if (this.entropy == null) {
+            // Use APR to get a crypto secure entropy value
+            byte[] result = new byte[32];
+            boolean apr = false;
+            try {
+                String methodName = "random";
+                Class paramTypes[] = new Class[2];
+                paramTypes[0] = result.getClass();
+                paramTypes[1] = int.class;
+                Object paramValues[] = new Object[2];
+                paramValues[0] = result;
+                paramValues[1] = new Integer(32);
+                Method method = Class.forName("org.apache.tomcat.jni.OS")
+                    .getMethod(methodName, paramTypes);
+                method.invoke(null, paramValues);
+                apr = true;
+            } catch (Throwable t) {
+                // Ignore
+            }
+            if (apr) {
+                setEntropy(new String(result));
+            } else {
+                setEntropy(this.toString());
+            }
+        }
+
+        return (this.entropy);
+
+    }
+
+
+    /**
+     * Set the entropy increaser value.
+     *
+     * @param entropy The new entropy increaser value
+     */
+    public void setEntropy(String entropy) {
+        this.entropy = entropy;
+    }
+
+
+    /**
+     * Return the random number generator class name.
+     */
+    public String getRandomClass() {
+
+        return (this.randomClass);
+
+    }
+
+
+    /**
+     * Set the random number generator class name.
+     *
+     * @param randomClass The new random number generator class name
+     */
+    public void setRandomClass(String randomClass) {
+        this.randomClass = randomClass;
+    }
+    
+    /**
+     * The Java class name of the random number generator class to be used
+     * when generating session identifiers.
+     */
+    protected String randomClass = "java.security.SecureRandom";
+    /** 
+     * Use /dev/random-type special device. This is new code, but may reduce
+     * the big delay in generating the random.
+     *
+     *  You must specify a path to a random generator file. Use /dev/urandom
+     *  for linux ( or similar ) systems. Use /dev/random for maximum security
+     *  ( it may block if not enough "random" exist ). You can also use
+     *  a pipe that generates random.
+     *
+     *  The code will check if the file exists, and default to java Random
+     *  if not found. There is a significant performance difference, very
+     *  visible on the first call to getSession ( like in the first JSP )
+     *  - so use it if available.
+     */
+    public void setRandomFile( String s ) {
+        // as a hack, you can use a static file - and genarate the same
+        // session ids ( good for strange debugging )
+        try{
+            devRandomSource=s;
+            File f=new File( devRandomSource );
+            if( ! f.exists() ) return;
+            randomIS= new DataInputStream( new FileInputStream(f));
+            randomIS.readLong();
+            if( log.isDebugEnabled() )
+                log.debug( "Opening " + devRandomSource );
+        } catch( IOException ex ) {
+            try {
+                randomIS.close();
+            } catch (Exception e) {
+                log.warn("Failed to close randomIS.");
+            }
+            
+            randomIS=null;
+        }
+    }
+
+    public String getRandomFile() {
+        return devRandomSource;
+    }
+
+
+    /**
+     * Gets the session id length (in bytes) of Sessions created by
+     * this Manager.
+     *
+     * @return The session id length
+     */
+    public int getSessionIdLength() {
+
+        return (this.sessionIdLength);
+
+    }
+
+
+    /**
+     * Sets the session id length (in bytes) for Sessions created by this
+     * Manager.
+     *
+     * @param idLength The session id length
+     */
+    public void setSessionIdLength(int idLength) {
+        this.sessionIdLength = idLength;
+    }
+}
\ No newline at end of file

Modified: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/session/SessionManagerServlet.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/session/SessionManagerServlet.java?view=diff&rev=534293&r1=534292&r2=534293
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/session/SessionManagerServlet.java (original)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/session/SessionManagerServlet.java Tue May  1 19:22:45 2007
@@ -35,7 +35,6 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.tomcat.servlets.util.RandomGenerator;
 
 // TODO: move 'expiring objects' to a separate utility class
 // TODO: hook the background thread

Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/DomUtil.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/DomUtil.java?view=auto&rev=534293
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/DomUtil.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/DomUtil.java Tue May  1 19:22:45 2007
@@ -0,0 +1,269 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tomcat.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StringReader;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+
+/**
+ *  Few simple utils to read DOM
+ *
+ * @author Costin Manolache
+ */
+public class DomUtil {
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( DomUtil.class );
+
+    // -------------------- DOM utils --------------------
+
+    /** Get the trimed text content of a node or null if there is no text
+     */
+    public static String getContent(Node n ) {
+        if( n==null ) return null;
+        Node n1=DomUtil.getChild(n, Node.TEXT_NODE);
+
+        if( n1==null ) return null;
+
+        String s1=n1.getNodeValue();
+        return s1.trim();
+    }
+
+    /** Get the first element child.
+     * @param parent lookup direct childs
+     * @param name name of the element. If null return the first element.
+     */
+    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( node.getNodeType()!=Node.ELEMENT_NODE)
+                continue;
+            if( name != null &&
+                name.equals( node.getNodeName() ) ) {
+                return node;
+            }
+            if( name == null ) {
+                return node;
+            }
+        }
+        return null;
+    }
+
+    public static String getAttribute(Node element, String attName ) {
+        NamedNodeMap attrs=element.getAttributes();
+        if( attrs==null ) return null;
+        Node attN=attrs.getNamedItem(attName);
+        if( attN==null ) return null;
+        return attN.getNodeValue();
+    }
+
+    public static void setAttribute(Node node, String attName, String val) {
+        NamedNodeMap attributes=node.getAttributes();
+        Node attNode=node.getOwnerDocument().createAttribute(attName);
+        attNode.setNodeValue( val );
+        attributes.setNamedItem(attNode);
+    }
+    
+    public static void removeAttribute( Node node, String attName ) {
+        NamedNodeMap attributes=node.getAttributes();
+        attributes.removeNamedItem(attName);                
+    }
+    
+    
+    /** Set or replace the text value 
+     */ 
+    public static void setText(Node node, String val) {
+        Node chld=DomUtil.getChild(node, Node.TEXT_NODE);
+        if( chld == null ) {
+            Node textN=node.getOwnerDocument().createTextNode(val);
+            node.appendChild(textN);
+            return;
+        }
+        // change the value
+        chld.setNodeValue(val);           
+    }
+
+    /** Find the first direct child with a given attribute.
+     * @param parent
+     * @param elemName name of the element, or null for any 
+     * @param attName attribute we're looking for
+     * @param attVal attribute value or null if we just want any
+     */ 
+    public static Node findChildWithAtt(Node parent, String elemName,
+                                        String attName, String attVal) {
+        
+        Node child=DomUtil.getChild(parent, Node.ELEMENT_NODE);
+        if( attVal== null ) {
+            while( child!= null &&
+                    ( elemName==null || elemName.equals( child.getNodeName())) && 
+                    DomUtil.getAttribute(child, attName) != null ) {
+                child=getNext(child, elemName, Node.ELEMENT_NODE );
+            }
+        } else {
+            while( child!= null && 
+                    ( elemName==null || elemName.equals( child.getNodeName())) && 
+                    ! attVal.equals( DomUtil.getAttribute(child, attName)) ) {
+                child=getNext(child, elemName, Node.ELEMENT_NODE );
+            }
+        }
+        return child;        
+    }    
+    
+
+    /** Get the first child's content ( ie 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 first direct child with a given type
+     */
+    public static Node getChild( Node parent, int type ) {
+        Node n=parent.getFirstChild();
+        while( n!=null && type != n.getNodeType() ) {
+            n=n.getNextSibling();
+        }
+        if( n==null ) return null;
+        return n;
+    }
+
+    /** Get the next sibling with the same name and type
+     */
+    public static Node getNext( Node current ) {
+        String name=current.getNodeName();
+        int type=current.getNodeType();
+        return getNext( current, name, type);
+    }
+
+    /** Return the next sibling with a given name and type
+     */ 
+    public static Node getNext( Node current, String name, int type) {
+        Node first=current.getNextSibling();
+        if( first==null ) return null;
+
+        for (Node node = first; node != null;
+             node = node.getNextSibling()) {
+            
+            if( type >= 0 && node.getNodeType() != type ) continue;
+            //System.out.println("getNode: " + name + " " + node.getNodeName());
+            if( name==null )
+                return node;
+            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.isTraceEnabled())
+                log.trace("ResolveEntity: " + publicId + " " + systemId);
+            return new InputSource(new StringReader(""));
+        }
+    }
+
+    public static void setAttributes( Object o, Node parent)
+    {
+        NamedNodeMap attrs=parent.getAttributes();
+        if( attrs==null ) return;
+
+        for (int i=0; i<attrs.getLength(); i++ ) {
+            Node n=attrs.item(i);
+            String name=n.getNodeName();
+            String value=n.getNodeValue();
+
+            if( log.isTraceEnabled() )
+                log.trace("Attribute " + parent.getNodeName() + " " +
+                            name + "=" + value);
+            try {
+                IntrospectionUtils.setProperty(o, name, value);
+            } catch( Exception ex ) {
+                ex.printStackTrace();
+            }
+        }
+    }
+
+    /** Read XML as DOM.
+     */
+    public static Document readXml(InputStream is)
+        throws SAXException, IOException, ParserConfigurationException
+    {
+        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(is);
+        return doc;
+    }
+
+    public static void writeXml( Node n, OutputStream os )
+            throws TransformerException
+    {
+        TransformerFactory tf=TransformerFactory.newInstance();
+        //identity
+        Transformer t=tf.newTransformer();
+        t.setOutputProperty(OutputKeys.INDENT, "yes");
+        t.transform(new DOMSource( n ), new StreamResult( os ));
+    }
+}

Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/IntrospectionUtils.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/IntrospectionUtils.java?view=auto&rev=534293
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/IntrospectionUtils.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/IntrospectionUtils.java Tue May  1 19:22:45 2007
@@ -0,0 +1,1001 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tomcat.util;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+// Depends: JDK1.1
+
+/**
+ * Utils for introspection and reflection
+ */
+public final class IntrospectionUtils {
+
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( IntrospectionUtils.class );
+    
+    /**
+     * Call execute() - any ant-like task should work
+     */
+    public static void execute(Object proxy, String method) throws Exception {
+        Method executeM = null;
+        Class c = proxy.getClass();
+        Class params[] = new Class[0];
+        //	params[0]=args.getClass();
+        executeM = findMethod(c, method, params);
+        if (executeM == null) {
+            throw new RuntimeException("No execute in " + proxy.getClass());
+        }
+        executeM.invoke(proxy, (Object[]) null);//new Object[] { args });
+    }
+
+    /**
+     * Call void setAttribute( String ,Object )
+     */
+    public static void setAttribute(Object proxy, String n, Object v)
+            throws Exception {
+        if (proxy instanceof AttributeHolder) {
+            ((AttributeHolder) proxy).setAttribute(n, v);
+            return;
+        }
+
+        Method executeM = null;
+        Class c = proxy.getClass();
+        Class params[] = new Class[2];
+        params[0] = String.class;
+        params[1] = Object.class;
+        executeM = findMethod(c, "setAttribute", params);
+        if (executeM == null) {
+            if (log.isDebugEnabled())
+                log.debug("No setAttribute in " + proxy.getClass());
+            return;
+        }
+        if (false)
+            if (log.isDebugEnabled())
+                log.debug("Setting " + n + "=" + v + "  in " + proxy);
+        executeM.invoke(proxy, new Object[] { n, v });
+        return;
+    }
+
+    /**
+     * Call void getAttribute( String )
+     */
+    public static Object getAttribute(Object proxy, String n) throws Exception {
+        Method executeM = null;
+        Class c = proxy.getClass();
+        Class params[] = new Class[1];
+        params[0] = String.class;
+        executeM = findMethod(c, "getAttribute", params);
+        if (executeM == null) {
+            if (log.isDebugEnabled())
+                log.debug("No getAttribute in " + proxy.getClass());
+            return null;
+        }
+        return executeM.invoke(proxy, new Object[] { n });
+    }
+
+    /**
+     * Construct a URLClassLoader. Will compile and work in JDK1.1 too.
+     */
+    public static ClassLoader getURLClassLoader(URL urls[], ClassLoader parent) {
+        try {
+            Class urlCL = Class.forName("java.net.URLClassLoader");
+            Class paramT[] = new Class[2];
+            paramT[0] = urls.getClass();
+            paramT[1] = ClassLoader.class;
+            Method m = findMethod(urlCL, "newInstance", paramT);
+            if (m == null)
+                return null;
+
+            ClassLoader cl = (ClassLoader) m.invoke(urlCL, new Object[] { urls,
+                    parent });
+            return cl;
+        } catch (ClassNotFoundException ex) {
+            // jdk1.1
+            return null;
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            return null;
+        }
+    }
+
+    public static String guessInstall(String installSysProp,
+            String homeSysProp, String jarName) {
+        return guessInstall(installSysProp, homeSysProp, jarName, null);
+    }
+
+    /**
+     * Guess a product install/home by analyzing the class path. It works for
+     * product using the pattern: lib/executable.jar or if executable.jar is
+     * included in classpath by a shell script. ( java -jar also works )
+     * 
+     * Insures both "install" and "home" System properties are set. If either or
+     * both System properties are unset, "install" and "home" will be set to the
+     * same value. This value will be the other System property that is set, or
+     * the guessed value if neither is set.
+     */
+    public static String guessInstall(String installSysProp,
+            String homeSysProp, String jarName, String classFile) {
+        String install = null;
+        String home = null;
+
+        if (installSysProp != null)
+            install = System.getProperty(installSysProp);
+
+        if (homeSysProp != null)
+            home = System.getProperty(homeSysProp);
+
+        if (install != null) {
+            if (home == null)
+                System.getProperties().put(homeSysProp, install);
+            return install;
+        }
+
+        // Find the directory where jarName.jar is located
+
+        String cpath = System.getProperty("java.class.path");
+        String pathSep = System.getProperty("path.separator");
+        StringTokenizer st = new StringTokenizer(cpath, pathSep);
+        while (st.hasMoreTokens()) {
+            String path = st.nextToken();
+            //	    log( "path " + path );
+            if (path.endsWith(jarName)) {
+                home = path.substring(0, path.length() - jarName.length());
+                try {
+                    if ("".equals(home)) {
+                        home = new File("./").getCanonicalPath();
+                    } else if (home.endsWith(File.separator)) {
+                        home = home.substring(0, home.length() - 1);
+                    }
+                    File f = new File(home);
+                    String parentDir = f.getParent();
+                    if (parentDir == null)
+                        parentDir = home; // unix style
+                    File f1 = new File(parentDir);
+                    install = f1.getCanonicalPath();
+                    if (installSysProp != null)
+                        System.getProperties().put(installSysProp, install);
+                    if (home == null && homeSysProp != null)
+                        System.getProperties().put(homeSysProp, install);
+                    return install;
+                } catch (Exception ex) {
+                    ex.printStackTrace();
+                }
+            } else {
+                String fname = path + (path.endsWith("/") ? "" : "/")
+                        + classFile;
+                if (new File(fname).exists()) {
+                    try {
+                        File f = new File(path);
+                        String parentDir = f.getParent();
+                        if (parentDir == null)
+                            parentDir = path; // unix style
+                        File f1 = new File(parentDir);
+                        install = f1.getCanonicalPath();
+                        if (installSysProp != null)
+                            System.getProperties().put(installSysProp, install);
+                        if (home == null && homeSysProp != null)
+                            System.getProperties().put(homeSysProp, install);
+                        return install;
+                    } catch (Exception ex) {
+                        ex.printStackTrace();
+                    }
+                }
+            }
+        }
+
+        // if install directory can't be found, use home as the default
+        if (home != null) {
+            System.getProperties().put(installSysProp, home);
+            return home;
+        }
+
+        return null;
+    }
+
+    /**
+     * Debug method, display the classpath
+     */
+    public static void displayClassPath(String msg, URL[] cp) {
+        if (log.isDebugEnabled()) {
+            log.debug(msg);
+            for (int i = 0; i < cp.length; i++) {
+                log.debug(cp[i].getFile());
+            }
+        }
+    }
+
+    public static String PATH_SEPARATOR = System.getProperty("path.separator");
+
+    /**
+     * Adds classpath entries from a vector of URL's to the "tc_path_add" System
+     * property. This System property lists the classpath entries common to web
+     * applications. This System property is currently used by Jasper when its
+     * JSP servlet compiles the Java file for a JSP.
+     */
+    public static String classPathAdd(URL urls[], String cp) {
+        if (urls == null)
+            return cp;
+
+        for (int i = 0; i < urls.length; i++) {
+            if (cp != null)
+                cp += PATH_SEPARATOR + urls[i].getFile();
+            else
+                cp = urls[i].getFile();
+        }
+        return cp;
+    }
+
+    /**
+     * Find a method with the right name If found, call the method ( if param is
+     * int or boolean we'll convert value to the right type before) - that means
+     * you can have setDebug(1).
+     */
+    public static void setProperty(Object o, String name, String value) {
+        if (dbg > 1)
+            d("setProperty(" + o.getClass() + " " + name + "=" + value + ")");
+
+        String setter = "set" + capitalize(name);
+
+        try {
+            Method methods[] = findMethods(o.getClass());
+            Method setPropertyMethod = null;
+
+            // First, the ideal case - a setFoo( String ) method
+            for (int i = 0; i < methods.length; i++) {
+                Class paramT[] = methods[i].getParameterTypes();
+                if (setter.equals(methods[i].getName()) && paramT.length == 1
+                        && "java.lang.String".equals(paramT[0].getName())) {
+
+                    methods[i].invoke(o, new Object[] { value });
+                    return;
+                }
+            }
+
+            // Try a setFoo ( int ) or ( boolean )
+            for (int i = 0; i < methods.length; i++) {
+                boolean ok = true;
+                if (setter.equals(methods[i].getName())
+                        && methods[i].getParameterTypes().length == 1) {
+
+                    // match - find the type and invoke it
+                    Class paramType = methods[i].getParameterTypes()[0];
+                    Object params[] = new Object[1];
+
+                    // Try a setFoo ( int )
+                    if ("java.lang.Integer".equals(paramType.getName())
+                            || "int".equals(paramType.getName())) {
+                        try {
+                            params[0] = new Integer(value);
+                        } catch (NumberFormatException ex) {
+                            ok = false;
+                        }
+                    // Try a setFoo ( long )
+                    }else if ("java.lang.Long".equals(paramType.getName())
+                                || "long".equals(paramType.getName())) {
+                            try {
+                                params[0] = new Long(value);
+                            } catch (NumberFormatException ex) {
+                                ok = false;
+                            }
+
+                        // Try a setFoo ( boolean )
+                    } else if ("java.lang.Boolean".equals(paramType.getName())
+                            || "boolean".equals(paramType.getName())) {
+                        params[0] = new Boolean(value);
+
+                        // Try a setFoo ( InetAddress )
+                    } else if ("java.net.InetAddress".equals(paramType
+                            .getName())) {
+                        try {
+                            params[0] = InetAddress.getByName(value);
+                        } catch (UnknownHostException exc) {
+                            d("Unable to resolve host name:" + value);
+                            ok = false;
+                        }
+
+                        // Unknown type
+                    } else {
+                        d("Unknown type " + paramType.getName());
+                    }
+
+                    if (ok) {
+                        methods[i].invoke(o, params);
+                        return;
+                    }
+                }
+
+                // save "setProperty" for later
+                if ("setProperty".equals(methods[i].getName())) {
+                    setPropertyMethod = methods[i];
+                }
+            }
+
+            // Ok, no setXXX found, try a setProperty("name", "value")
+            if (setPropertyMethod != null) {
+                Object params[] = new Object[2];
+                params[0] = name;
+                params[1] = value;
+                setPropertyMethod.invoke(o, params);
+            }
+
+        } catch (IllegalArgumentException ex2) {
+            log.warn("IAE " + o + " " + name + " " + value, ex2);
+        } catch (SecurityException ex1) {
+            if (dbg > 0)
+                d("SecurityException for " + o.getClass() + " " + name + "="
+                        + value + ")");
+            if (dbg > 1)
+                ex1.printStackTrace();
+        } catch (IllegalAccessException iae) {
+            if (dbg > 0)
+                d("IllegalAccessException for " + o.getClass() + " " + name
+                        + "=" + value + ")");
+            if (dbg > 1)
+                iae.printStackTrace();
+        } catch (InvocationTargetException ie) {
+            if (dbg > 0)
+                d("InvocationTargetException for " + o.getClass() + " " + name
+                        + "=" + value + ")");
+            if (dbg > 1)
+                ie.printStackTrace();
+        }
+    }
+
+    public static Object getProperty(Object o, String name) {
+        String getter = "get" + capitalize(name);
+        String isGetter = "is" + capitalize(name);
+
+        try {
+            Method methods[] = findMethods(o.getClass());
+            Method getPropertyMethod = null;
+
+            // First, the ideal case - a getFoo() method
+            for (int i = 0; i < methods.length; i++) {
+                Class paramT[] = methods[i].getParameterTypes();
+                if (getter.equals(methods[i].getName()) && paramT.length == 0) {
+                    return methods[i].invoke(o, (Object[]) null);
+                }
+                if (isGetter.equals(methods[i].getName()) && paramT.length == 0) {
+                    return methods[i].invoke(o, (Object[]) null);
+                }
+
+                if ("getProperty".equals(methods[i].getName())) {
+                    getPropertyMethod = methods[i];
+                }
+            }
+
+            // Ok, no setXXX found, try a getProperty("name")
+            if (getPropertyMethod != null) {
+                Object params[] = new Object[1];
+                params[0] = name;
+                return getPropertyMethod.invoke(o, params);
+            }
+
+        } catch (IllegalArgumentException ex2) {
+            log.warn("IAE " + o + " " + name, ex2);
+        } catch (SecurityException ex1) {
+            if (dbg > 0)
+                d("SecurityException for " + o.getClass() + " " + name + ")");
+            if (dbg > 1)
+                ex1.printStackTrace();
+        } catch (IllegalAccessException iae) {
+            if (dbg > 0)
+                d("IllegalAccessException for " + o.getClass() + " " + name
+                        + ")");
+            if (dbg > 1)
+                iae.printStackTrace();
+        } catch (InvocationTargetException ie) {
+            if (dbg > 0)
+                d("InvocationTargetException for " + o.getClass() + " " + name
+                        + ")");
+            if (dbg > 1)
+                ie.printStackTrace();
+        }
+        return null;
+    }
+
+    /** 
+     */
+    public static void setProperty(Object o, String name) {
+        String setter = "set" + capitalize(name);
+        try {
+            Method methods[] = findMethods(o.getClass());
+            Method setPropertyMethod = null;
+            // find setFoo() method
+            for (int i = 0; i < methods.length; i++) {
+                Class paramT[] = methods[i].getParameterTypes();
+                if (setter.equals(methods[i].getName()) && paramT.length == 0) {
+                    methods[i].invoke(o, new Object[] {});
+                    return;
+                }
+            }
+        } catch (Exception ex1) {
+            if (dbg > 0)
+                d("Exception for " + o.getClass() + " " + name);
+            if (dbg > 1)
+                ex1.printStackTrace();
+        }
+    }
+
+    /**
+     * Replace ${NAME} with the property value
+     * 
+     * @deprecated Use the explicit method
+     */
+    public static String replaceProperties(String value, Object getter) {
+        if (getter instanceof Hashtable)
+            return replaceProperties(value, (Hashtable) getter, null);
+
+        if (getter instanceof PropertySource) {
+            PropertySource src[] = new PropertySource[] { (PropertySource) getter };
+            return replaceProperties(value, null, src);
+        }
+        return value;
+    }
+
+    /**
+     * Replace ${NAME} with the property value
+     */
+    public static String replaceProperties(String value, Hashtable staticProp,
+            PropertySource dynamicProp[]) {
+        StringBuffer sb = new StringBuffer();
+        int prev = 0;
+        // assert value!=nil
+        int pos;
+        while ((pos = value.indexOf("$", prev)) >= 0) {
+            if (pos > 0) {
+                sb.append(value.substring(prev, pos));
+            }
+            if (pos == (value.length() - 1)) {
+                sb.append('$');
+                prev = pos + 1;
+            } else if (value.charAt(pos + 1) != '{') {
+                sb.append('$');
+                prev = pos + 1; // XXX
+            } else {
+                int endName = value.indexOf('}', pos);
+                if (endName < 0) {
+                    sb.append(value.substring(pos));
+                    prev = value.length();
+                    continue;
+                }
+                String n = value.substring(pos + 2, endName);
+                String v = null;
+                if (staticProp != null) {
+                    v = (String) ((Hashtable) staticProp).get(n);
+                }
+                if (v == null && dynamicProp != null) {
+                    for (int i = 0; i < dynamicProp.length; i++) {
+                        v = dynamicProp[i].getProperty(n);
+                        if (v != null) {
+                            break;
+                        }
+                    }
+                }
+                if (v == null)
+                    v = "${" + n + "}";
+
+                sb.append(v);
+                prev = endName + 1;
+            }
+        }
+        if (prev < value.length())
+            sb.append(value.substring(prev));
+        return sb.toString();
+    }
+
+    /**
+     * Reverse of Introspector.decapitalize
+     */
+    public static String capitalize(String name) {
+        if (name == null || name.length() == 0) {
+            return name;
+        }
+        char chars[] = name.toCharArray();
+        chars[0] = Character.toUpperCase(chars[0]);
+        return new String(chars);
+    }
+
+    public static String unCapitalize(String name) {
+        if (name == null || name.length() == 0) {
+            return name;
+        }
+        char chars[] = name.toCharArray();
+        chars[0] = Character.toLowerCase(chars[0]);
+        return new String(chars);
+    }
+
+    // -------------------- Class path tools --------------------
+
+    /**
+     * Add all the jar files in a dir to the classpath, represented as a Vector
+     * of URLs.
+     */
+    public static void addToClassPath(Vector cpV, String dir) {
+        try {
+            String cpComp[] = getFilesByExt(dir, ".jar");
+            if (cpComp != null) {
+                int jarCount = cpComp.length;
+                for (int i = 0; i < jarCount; i++) {
+                    URL url = getURL(dir, cpComp[i]);
+                    if (url != null)
+                        cpV.addElement(url);
+                }
+            }
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    public static void addToolsJar(Vector v) {
+        try {
+            // Add tools.jar in any case
+            File f = new File(System.getProperty("java.home")
+                    + "/../lib/tools.jar");
+
+            if (!f.exists()) {
+                // On some systems java.home gets set to the root of jdk.
+                // That's a bug, but we can work around and be nice.
+                f = new File(System.getProperty("java.home") + "/lib/tools.jar");
+                if (f.exists()) {
+                    if (log.isDebugEnabled())
+                        log.debug("Detected strange java.home value "
+                            + System.getProperty("java.home")
+                            + ", it should point to jre");
+                }
+            }
+            URL url = new URL("file", "", f.getAbsolutePath());
+
+            v.addElement(url);
+        } catch (MalformedURLException ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    /**
+     * Return all files with a given extension in a dir
+     */
+    public static String[] getFilesByExt(String ld, String ext) {
+        File dir = new File(ld);
+        String[] names = null;
+        final String lext = ext;
+        if (dir.isDirectory()) {
+            names = dir.list(new FilenameFilter() {
+                public boolean accept(File d, String name) {
+                    if (name.endsWith(lext)) {
+                        return true;
+                    }
+                    return false;
+                }
+            });
+        }
+        return names;
+    }
+
+    /**
+     * Construct a file url from a file, using a base dir
+     */
+    public static URL getURL(String base, String file) {
+        try {
+            File baseF = new File(base);
+            File f = new File(baseF, file);
+            String path = f.getCanonicalPath();
+            if (f.isDirectory()) {
+                path += "/";
+            }
+            if (!f.exists())
+                return null;
+            return new URL("file", "", path);
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * Add elements from the classpath <i>cp </i> to a Vector <i>jars </i> as
+     * file URLs (We use Vector for JDK 1.1 compat).
+     * <p>
+     * 
+     * @param jars The jar list
+     * @param cp a String classpath of directory or jar file elements
+     *   separated by path.separator delimiters.
+     * @throws IOException If an I/O error occurs
+     * @throws MalformedURLException Doh ;)
+     */
+    public static void addJarsFromClassPath(Vector jars, String cp)
+            throws IOException, MalformedURLException {
+        String sep = System.getProperty("path.separator");
+        String token;
+        StringTokenizer st;
+        if (cp != null) {
+            st = new StringTokenizer(cp, sep);
+            while (st.hasMoreTokens()) {
+                File f = new File(st.nextToken());
+                String path = f.getCanonicalPath();
+                if (f.isDirectory()) {
+                    path += "/";
+                }
+                URL url = new URL("file", "", path);
+                if (!jars.contains(url)) {
+                    jars.addElement(url);
+                }
+            }
+        }
+    }
+
+    /**
+     * Return a URL[] that can be used to construct a class loader
+     */
+    public static URL[] getClassPath(Vector v) {
+        URL[] urls = new URL[v.size()];
+        for (int i = 0; i < v.size(); i++) {
+            urls[i] = (URL) v.elementAt(i);
+        }
+        return urls;
+    }
+
+    /**
+     * Construct a URL classpath from files in a directory, a cpath property,
+     * and tools.jar.
+     */
+    public static URL[] getClassPath(String dir, String cpath,
+            String cpathProp, boolean addTools) throws IOException,
+            MalformedURLException {
+        Vector jarsV = new Vector();
+        if (dir != null) {
+            // Add dir/classes first, if it exists
+            URL url = getURL(dir, "classes");
+            if (url != null)
+                jarsV.addElement(url);
+            addToClassPath(jarsV, dir);
+        }
+
+        if (cpath != null)
+            addJarsFromClassPath(jarsV, cpath);
+
+        if (cpathProp != null) {
+            String cpath1 = System.getProperty(cpathProp);
+            addJarsFromClassPath(jarsV, cpath1);
+        }
+
+        if (addTools)
+            addToolsJar(jarsV);
+
+        return getClassPath(jarsV);
+    }
+
+    // -------------------- Mapping command line params to setters
+
+    /** 
+     * Easy way to map args[] to java-bean style method calls. Makes it
+     * easy to document and allow programmatic access.
+     * 
+     * The pattern is ant - a bunch of setters and an execute method.
+     * 
+     * Syntax:
+     *   -arg1 -arg2 val2 -arg3=val3 -noarg4
+     *   
+     * @param proxy object where the setters will be called
+     * @param args  command line arguments
+     */
+    public static boolean processArgs(Object proxy, String[] args) 
+        throws Exception {
+      
+      String[] args0 = findBooleanSetters(proxy.getClass());
+      List noargs = new ArrayList();
+      
+      for (int i = 0; i < args.length; i++) {
+        String arg = args[i];
+        if (! arg.startsWith("-")) {
+          noargs.add(arg);
+          continue;
+        }
+
+        if (arg.startsWith("--")) { 
+          arg = arg.substring(2).toLowerCase();
+        } else {
+          arg = arg.substring(1).toLowerCase();
+        }
+        
+        for (int j = 0; j < args0.length; j++) {
+          if (args0[j].equalsIgnoreCase(arg)) {
+            setProperty(proxy, args0[j], "true");
+            continue;
+          }
+        }
+
+        String val = null;
+        int eqIdx = arg.indexOf('=');
+        if (eqIdx > 0) {
+          val = arg.substring(eqIdx);
+          arg = arg.substring(0, eqIdx);
+        } else {
+          i++;
+          if (i >= args.length) {
+            throw new RuntimeException("Missing argument for " + arg);
+          }
+          val = args[i];
+        }
+        // will fail if property missing
+        setProperty(proxy, arg, val);
+      }
+      return true;
+    }
+
+    // -------------------- other utils --------------------
+    public static void clear() {
+        objectMethods.clear();
+    }
+    
+    public static String[] findVoidSetters(Class c) {
+        Method m[] = findMethods(c);
+        if (m == null)
+            return null;
+        Vector v = new Vector();
+        for (int i = 0; i < m.length; i++) {
+            if (m[i].getName().startsWith("set")
+                    && m[i].getParameterTypes().length == 0) {
+                String arg = m[i].getName().substring(3);
+                v.addElement(unCapitalize(arg));
+            }
+        }
+        String s[] = new String[v.size()];
+        for (int i = 0; i < s.length; i++) {
+            s[i] = (String) v.elementAt(i);
+        }
+        return s;
+    }
+
+    /** 
+     * For no-arg parameters.
+     */
+    public static String[] findBooleanSetters(Class c) {
+        Method m[] = findMethods(c);
+        if (m == null)
+            return null;
+        Vector v = new Vector();
+        for (int i = 0; i < m.length; i++) {
+            if (m[i].getName().startsWith("set")
+                    && m[i].getParameterTypes().length == 1
+                    && "boolean".equalsIgnoreCase(m[i].getParameterTypes()[0]
+                            .getName())) {
+                String arg = m[i].getName().substring(3);
+                v.addElement(unCapitalize(arg));
+            }
+        }
+        String s[] = new String[v.size()];
+        for (int i = 0; i < s.length; i++) {
+            s[i] = (String) v.elementAt(i);
+        }
+        return s;
+    }
+
+    static Hashtable objectMethods = new Hashtable();
+
+    public static Method[] findMethods(Class c) {
+        Method methods[] = (Method[]) objectMethods.get(c);
+        if (methods != null)
+            return methods;
+
+        methods = c.getMethods();
+        objectMethods.put(c, methods);
+        return methods;
+    }
+
+    public static Method findMethod(Class c, String name, Class params[]) {
+        Method methods[] = findMethods(c);
+        if (methods == null)
+            return null;
+        for (int i = 0; i < methods.length; i++) {
+            if (methods[i].getName().equals(name)) {
+                Class methodParams[] = methods[i].getParameterTypes();
+                if (methodParams == null)
+                    if (params == null || params.length == 0)
+                        return methods[i];
+                if (params == null)
+                    if (methodParams == null || methodParams.length == 0)
+                        return methods[i];
+                if (params.length != methodParams.length)
+                    continue;
+                boolean found = true;
+                for (int j = 0; j < params.length; j++) {
+                    if (params[j] != methodParams[j]) {
+                        found = false;
+                        break;
+                    }
+                }
+                if (found)
+                    return methods[i];
+            }
+        }
+        return null;
+    }
+
+    /** Test if the object implements a particular
+     *  method
+     */
+    public static boolean hasHook(Object obj, String methodN) {
+        try {
+            Method myMethods[] = findMethods(obj.getClass());
+            for (int i = 0; i < myMethods.length; i++) {
+                if (methodN.equals(myMethods[i].getName())) {
+                    // check if it's overriden
+                    Class declaring = myMethods[i].getDeclaringClass();
+                    Class parentOfDeclaring = declaring.getSuperclass();
+                    // this works only if the base class doesn't extend
+                    // another class.
+
+                    // if the method is declared in a top level class
+                    // like BaseInterceptor parent is Object, otherwise
+                    // parent is BaseInterceptor or an intermediate class
+                    if (!"java.lang.Object".equals(parentOfDeclaring.getName())) {
+                        return true;
+                    }
+                }
+            }
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+        return false;
+    }
+
+    public static void callMain(Class c, String args[]) throws Exception {
+        Class p[] = new Class[1];
+        p[0] = args.getClass();
+        Method m = c.getMethod("main", p);
+        m.invoke(c, new Object[] { args });
+    }
+
+    public static Object callMethod1(Object target, String methodN,
+            Object param1, String typeParam1, ClassLoader cl) throws Exception {
+        if (target == null || param1 == null) {
+            d("Assert: Illegal params " + target + " " + param1);
+        }
+        if (dbg > 0)
+            d("callMethod1 " + target.getClass().getName() + " "
+                    + param1.getClass().getName() + " " + typeParam1);
+
+        Class params[] = new Class[1];
+        if (typeParam1 == null)
+            params[0] = param1.getClass();
+        else
+            params[0] = cl.loadClass(typeParam1);
+        Method m = findMethod(target.getClass(), methodN, params);
+        if (m == null)
+            throw new NoSuchMethodException(target.getClass().getName() + " "
+                    + methodN);
+        return m.invoke(target, new Object[] { param1 });
+    }
+
+    public static Object callMethod0(Object target, String methodN)
+            throws Exception {
+        if (target == null) {
+            d("Assert: Illegal params " + target);
+            return null;
+        }
+        if (dbg > 0)
+            d("callMethod0 " + target.getClass().getName() + "." + methodN);
+
+        Class params[] = new Class[0];
+        Method m = findMethod(target.getClass(), methodN, params);
+        if (m == null)
+            throw new NoSuchMethodException(target.getClass().getName() + " "
+                    + methodN);
+        return m.invoke(target, emptyArray);
+    }
+
+    static Object[] emptyArray = new Object[] {};
+
+    public static Object callMethodN(Object target, String methodN,
+            Object params[], Class typeParams[]) throws Exception {
+        Method m = null;
+        m = findMethod(target.getClass(), methodN, typeParams);
+        if (m == null) {
+            d("Can't find method " + methodN + " in " + target + " CLASS "
+                    + target.getClass());
+            return null;
+        }
+        Object o = m.invoke(target, params);
+
+        if (dbg > 0) {
+            // debug
+            StringBuffer sb = new StringBuffer();
+            sb.append("" + target.getClass().getName() + "." + methodN + "( ");
+            for (int i = 0; i < params.length; i++) {
+                if (i > 0)
+                    sb.append(", ");
+                sb.append(params[i]);
+            }
+            sb.append(")");
+            d(sb.toString());
+        }
+        return o;
+    }
+
+    public static Object convert(String object, Class paramType) {
+        Object result = null;
+        if ("java.lang.String".equals(paramType.getName())) {
+            result = object;
+        } else if ("java.lang.Integer".equals(paramType.getName())
+                || "int".equals(paramType.getName())) {
+            try {
+                result = new Integer(object);
+            } catch (NumberFormatException ex) {
+            }
+            // Try a setFoo ( boolean )
+        } else if ("java.lang.Boolean".equals(paramType.getName())
+                || "boolean".equals(paramType.getName())) {
+            result = new Boolean(object);
+
+            // Try a setFoo ( InetAddress )
+        } else if ("java.net.InetAddress".equals(paramType
+                .getName())) {
+            try {
+                result = InetAddress.getByName(object);
+            } catch (UnknownHostException exc) {
+                d("Unable to resolve host name:" + object);
+            }
+
+            // Unknown type
+        } else {
+            d("Unknown type " + paramType.getName());
+        }
+        if (result == null) {
+            throw new IllegalArgumentException("Can't convert argument: " + object);
+        }
+        return result;
+    }
+    
+    // -------------------- Get property --------------------
+    // This provides a layer of abstraction
+
+    public static interface PropertySource {
+
+        public String getProperty(String key);
+
+    }
+
+    public static interface AttributeHolder {
+
+        public void setAttribute(String key, Object o);
+
+    }
+
+    // debug --------------------
+    static final int dbg = 0;
+
+    static void d(String s) {
+        if (log.isDebugEnabled())
+            log.debug("IntrospectionUtils: " + s);
+    }
+}

Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/buf/BBuffer.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/buf/BBuffer.java?view=auto&rev=534293
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/buf/BBuffer.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/util/buf/BBuffer.java Tue May  1 19:22:45 2007
@@ -0,0 +1,508 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tomcat.util.buf;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+
+
+/**
+ * Growable byte buffer, with write/read methods, used as the underlying 
+ * implementation for tomcat streams.
+ * 
+ * This wraps a java.nio.ByteBuffer, and adds ability to grow/flush and
+ * makes it easier to deal with read and write - no need to remember what 
+ * mode the buffer was. 
+ * 
+ * Refactored from ByteChunk - this is only the buffer part, without utils
+ * to operate on the buffer. Used in Http11Connection, MessageWriter, 
+ * MessageReader
+ * 
+ * @author Costin Manolache
+ */
+public final class BBuffer implements Cloneable, Serializable {
+
+    // --------------------
+
+    /** Default encoding used to convert to strings. It should be UTF8,
+	as most standards seem to converge, but the servlet API requires
+	8859_1, and this object is used mostly for servlets. 
+    */
+    public static final String DEFAULT_CHARACTER_ENCODING="ISO-8859-1";
+
+    // Default is for output, like ByteBuffer.
+    private boolean isOutput = true; 
+    private ByteBuffer bb;
+
+    private int start=0; // used as ByteBuffer.offset and position
+    private int end; // used as limit
+
+    
+    // How much can it grow, when data is added. Different from the bb limit,
+    // this is how much we can resize the bb before flushing.
+    private int growLimit=-1;
+
+    // maybe a single in/out channel would be better.
+    private ReadableByteChannel in = null;
+    private WritableByteChannel out = null;
+
+    /**
+     * Prealocate a buffer.
+     * Called by C2B, BufferedInputFilter ( mode 2 ), catalina InputBuffer 
+     * and OutputBuffe,  
+     * 
+     * @param initial
+     */
+    public BBuffer( int initial ) {
+        isOutput=true;
+        if( bb==null || bb.capacity() < initial ) {
+            bb=ByteBuffer.allocate(initial);
+        }    
+        this.growLimit = -1;
+        start=0;
+        end=0;
+    }
+
+    /** 
+     * Use the bb. Will start in read mode, never grow.
+     * 
+     * @param bb buffer in read mode
+     */
+    public BBuffer(ByteBuffer bb, ReadableByteChannel in, 
+                   WritableByteChannel out) {
+      this.bb = bb;
+      start = bb.position();
+      end = bb.limit();
+      isOutput = false;
+      growLimit = bb.capacity();
+      this.in = in;
+      this.out = out;
+    }
+
+    
+    /** 
+     * Access the underlying buffer for direct use. ReleaseBuffer must be 
+     * called when done writting to the buffer (if forWrite ) or reading
+     * ( if !forWrite). 
+     * 
+     * @param forWrite 
+     * @return
+     */
+    public ByteBuffer getBuffer(boolean forWrite) {
+        if( forWrite ) {
+          // start will be preserved, the buffer can't be used for read
+          // ( since that would go to 0 not start ).
+          if (isOutput) {
+            // should match the values in the buffer
+            bb.position(end);
+            bb.limit(bb.capacity());
+          } else {
+            isOutput = true;
+            bb.position(end);
+            bb.limit(bb.capacity());
+          }
+        } else {
+          if (isOutput) {
+            isOutput = false;
+            bb.position(start);
+            bb.limit(end);
+          } else {
+            bb.position(start);
+            bb.limit(end);            
+          }
+        }
+        return bb;
+    }
+
+    public void releaseBuffer() {
+        if( isOutput ) {
+          // start remain the same ( probably 0 )
+          end = bb.position();
+          bb.limit(bb.capacity());
+        } else {
+          isOutput = true;
+          // flip bb for reading
+          bb.limit(bb.position());
+          bb.position(0);
+        }
+    }
+    
+    /**
+     * Resets the message buff to an uninitialized state.
+     */
+    public void recycle() {
+      start=0;
+      end=0;
+      if( bb != null) bb.clear();
+      // mode remains - it shouldn't change
+      isOutput = true;
+    }
+
+    public void reset() {
+      bb=null;
+    }
+
+    // -------------------- Setup --------------------
+
+    /**
+     * Returns the message bytes.
+     */
+    public byte[] getBytes() {
+        return bb.array();
+    }
+
+    /**
+     * Returns the start offset of the bytes.
+     * For output this is the end of the buffer.
+     */
+    public int getStart() {
+	return start;
+    }
+
+    public void setStart(int off) {
+        if (end < off ) end=off;
+	start=off;
+    }
+
+
+    public int getEnd() {
+        return end;
+    }
+
+    public void setEnd( int i ) {
+        end=i;
+    }
+
+    /**
+     * Returns the length of the bytes.
+     */
+    public int getLength() {
+	return end-start;
+    }
+
+    /** 
+     * Maximum amount of data in this buffer.
+     *
+     *  If -1 or not set, the buffer will grow undefinitely.
+     *  Can be smaller than the current buffer size ( which will not shrink ).
+     *  When the limit is reached, the buffer will be flushed ( if out is set )
+     *  or throw exception.
+     */
+    public void setLimit(int limit) {
+	this.growLimit=limit;
+    }
+    
+    public int getLimit() {
+	return growLimit;
+    }
+
+    /**
+     * When the buffer is empty, read the data from the input channel.
+     */
+    public void setInputChannel(ReadableByteChannel in) {
+      this.in = in;
+    }
+
+    /** When the buffer is full, write the data to the output channel.
+     * 	Also used when large amount of data is appended.
+     *
+     *  If not set, the buffer will grow to the limit.
+     */
+    public void setByteOutputChannel(WritableByteChannel out) {
+	this.out=out;
+    }
+
+    // -------------------- Adding data to the buffer --------------------
+    
+    /** Append a char, by casting it to byte. This IS NOT intended for unicode.
+     *
+     * @param c
+     * @throws IOException
+     */
+    public void append( char c )
+	throws IOException
+    {
+	append( (byte)c);
+    }
+
+    public void append( byte b )
+	throws IOException
+    {
+	makeSpace( 1 );
+
+	// couldn't make space
+	if( growLimit >0 && end >= growLimit ) {
+	    flushBuffer();
+	}
+        bb.array()[end++] = b;
+    }
+
+    public void append( BBuffer src )
+	throws IOException
+    {
+	append( src.getBytes(), src.getStart(), src.getLength());
+    }
+    
+    public int append( InputStream is, int maxlen) throws IOException {
+      makeSpace(maxlen);
+      
+      int realRead = is.read(bb.array(), end, maxlen);
+      if ( realRead == -1) {
+        return -1;
+      }
+      end += realRead;
+      return realRead;
+    }
+
+    /** Add data to the buffer
+     */
+    public void append( byte src[], int off, int len )
+	throws IOException
+    {
+        // will grow, up to limit
+	makeSpace( len );
+
+	// if we don't have limit: makeSpace can grow as it wants
+	if( growLimit < 0 ) {
+	    // assert: makeSpace made enough space
+	    System.arraycopy( src, off, bb.array(), end, len );
+	    end+=len;
+	    return;
+	}
+
+        // Optimize on a common case.
+        // If the buffer is empty and the source is going to fill up all the
+        // space in buffer, may as well write it directly to the output,
+        // and avoid an extra copy
+        if (len == growLimit && end == start) {
+          out.write(ByteBuffer.wrap(src, off, len));
+          return;
+        }
+        
+	// if we have limit and we're below
+	if( len <= growLimit - end ) {
+	    // makeSpace will grow the buffer to the limit,
+	    // so we have space
+	    System.arraycopy( src, off, bb.array(), end, len );
+	    end+=len;
+	    return;
+	}
+
+	// need more space than we can afford, need to flush
+	// buffer
+
+	// the buffer is already at ( or bigger than ) limit
+
+        // We chunk the data into slices fitting in the buffer limit, although
+        // if the data is written directly if it doesn't fit
+
+        int avail=growLimit-end;
+        // to minimize the number of writes
+        System.arraycopy(src, off, bb.array(), end, avail);
+        end += avail;
+        flushBuffer();
+
+        //int remain = len - avail;
+
+        // Directly write the reminder
+        //while (remain > (growLimit - end)) {
+        //  out.write(ByteBuffer.wrap(src, (off+len) - remain, growLimit - end));
+        //  remain = remain - (growLimit - end);
+        //}
+
+        //System.arraycopy(src, (off + len) - remain, bb.array(), end, remain);
+        //end += remain;
+        // TODO: handle non-blocking channels 
+        out.write(ByteBuffer.wrap(src, off + avail, len - avail));
+    }
+
+    /** Send the buffer to the sink. Called by append() when the limit is reached.
+     *  You can also call it explicitely to force the data to be written.
+     *
+     * @throws IOException
+     */
+    public void flushBuffer()
+        throws IOException
+    {   
+      writeMode();
+      if( out==null ) {
+        throw new IOException( "Buffer overflow, no sink " + growLimit + " " +
+            bb.capacity()  );
+      }
+      getBuffer(false);
+      out.write(bb);
+      bb.clear();
+      isOutput = true;
+      //out.realWriteBytes( bb.array(), start, end-start );
+      start = end = 0;
+    }
+
+
+    /** Make space for len chars. If len is small, allocate
+     *  a reserve space too. Never grow bigger than limit.
+     */
+    private void makeSpace(int count)
+    {
+      writeMode();
+      ByteBuffer tmp = null;
+
+      int newSize;
+      int desiredSize=end + count;
+
+      // Can't grow above the limit
+      if( growLimit > 0 &&
+          desiredSize > growLimit) {
+        desiredSize=growLimit;
+      }
+
+      if( bb==null ) {
+        if( desiredSize < 256 ) desiredSize=256; // take a minimum
+        bb=ByteBuffer.allocate(desiredSize);
+      }
+
+      // limit < buf.length ( the buffer is already big )
+      // or we already have space XXX
+      if( desiredSize <= bb.capacity() ) {
+        return;
+      }
+      // grow in larger chunks
+      if( desiredSize < 2 * bb.capacity() ) {
+        newSize= bb.capacity() * 2;
+        if( growLimit >0 &&
+            newSize > growLimit ) newSize=growLimit;
+      } else {
+        newSize= bb.capacity() * 2 + count ;
+        if( growLimit > 0 &&
+            newSize > growLimit ) newSize=growLimit;
+      }
+      tmp=ByteBuffer.allocate(newSize);
+
+      System.arraycopy(bb.array(), start, tmp.array(), 0, end-start);
+      bb = tmp;
+      tmp = null;
+      end=end-start;
+      start=0;
+    }
+
+    // -------------------- Removing data from the buffer --------------------
+
+    /**
+     * 
+     */
+    private void readMode() {
+      if (isOutput) {
+        // flip
+        isOutput = false;
+        bb.flip(); // pos = 0, limit = end;
+        bb.limit(end); // should not be needed
+        bb.position(start); // pos = start, limit = end
+      }
+    }
+
+    private void writeMode() {
+      if (!isOutput) {
+        isOutput = true;
+        bb.limit(bb.capacity());
+        bb.position(end);
+      }
+    }
+    
+    public int substract()
+        throws IOException {
+
+        if ((end - start) == 0) {
+          if (in == null)
+            return -1;
+          int n = in.read(getBuffer(true));
+          releaseBuffer();
+
+          if (n < 0)
+            return -1;
+        }
+
+        readMode();
+        return (bb.array()[start++] & 0xFF);
+    }
+
+    public int substract(BBuffer src)
+        throws IOException {
+
+        if ((end - start) == 0) {
+            if (in == null)
+                return -1;
+            int n = in.read(getBuffer(true));
+            releaseBuffer();
+            if (n < 0)
+                return -1;
+        }
+
+        readMode();
+        int len = getLength();
+        src.append(bb.array(), start, len);
+        start = end;
+        return len;
+
+    }
+
+    public int substract( byte src[], int off, int len )
+        throws IOException {
+
+        if ((end - start) == 0) {
+            if (in == null)
+                return -1;
+            int n = in.read(getBuffer(true));
+            releaseBuffer();
+            if (n < 0)
+                return -1;
+        }
+
+        readMode();
+        int n = len;
+        if (len > getLength()) {
+            n = getLength();
+        }
+        System.arraycopy(bb.array(), start, src, off, n);
+        start += n;
+        return n;
+    }
+    
+    public int skip(int len) throws IOException {
+      readMode();
+      start += len;
+      return len;
+    }
+
+    /**
+     * Move the bytes starting with pos0 to beginning, adjust offsets.
+     * This is used after some content has been consummed. 
+     * 
+     * After this method, the buffer can be used for write.
+     * 
+     * @param pos0
+     */
+    public void compact() {
+      int pos0 = start;
+      System.arraycopy(bb.array(), pos0, bb.array(), 0, end - pos0);
+      end = end - pos0;
+      start = 0;
+      writeMode(); // bytes added at end.
+    }
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Mime
View raw message