You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by fa...@apache.org on 2004/01/19 07:59:56 UTC

cvs commit: avalon/merlin/platform/tutorials/simple-web/src/java/tutorial MalformedRequestException.java Reply.java Request.java RfcDateFormat.java SimpleConnectionHandler.java SimpleConnectionHandlerFactory.java SimpleWebServerComponent.java

farra       2004/01/18 22:59:56

  Added:       merlin/platform/tutorials/simple-web/conf block.xml
               merlin/platform/tutorials/simple-web maven.xml
                        project.properties project.xml
               merlin/platform/tutorials/simple-web/src/java/tutorial
                        MalformedRequestException.java Reply.java
                        Request.java RfcDateFormat.java
                        SimpleConnectionHandler.java
                        SimpleConnectionHandlerFactory.java
                        SimpleWebServerComponent.java
  Log:
  simple webserver using cornerstone components.
  Contributed by Timothy Bennett.
  Currently requires JDK 1.4
  
  Revision  Changes    Path
  1.1                  avalon/merlin/platform/tutorials/simple-web/conf/block.xml
  
  Index: block.xml
  ===================================================================
  <container name="my-web-server">
  
  	<categories priority="INFO">
  		<category name="classloader/scanner" priority="ERROR"/>
  		<category name="simple-web-server" priority="DEBUG"/>
      </categories>
  
      <classloader>
          <classpath>
              <repository>
                  <resource id="avalon-framework:avalon-framework-api" version="4.1.5"/>
                  <resource id="avalon-framework:avalon-framework-impl" version="4.1.5"/>
  				<resource id="commons-collections:commons-collections" version="2.1"/>
  				<resource id="excalibur-pool:excalibur-pool" version="1.2"/>
  				<resource id="excalibur-thread:excalibur-thread" version="1.1.1"/>
  				<resource id="excalibur-event:excalibur-event" version="1.0.3"/>
                  <resource id="cornerstone-sockets:cornerstone-sockets-api" version="1.0"/>
                  <resource id="cornerstone-sockets:cornerstone-sockets-impl" version="1.0"/>
                  <resource id="cornerstone-connection:cornerstone-connection-api" version="1.0"/>
                  <resource id="cornerstone-connection:cornerstone-connection-impl" version="1.0"/>
                  <resource id="cornerstone-threads:cornerstone-threads-api" version="1.0"/>
                  <resource id="cornerstone-threads:cornerstone-threads-impl" version="1.0"/>
              </repository>
          </classpath>
      </classloader>
  
  	<component name="thread-manager"
  			   class="org.apache.avalon.cornerstone.blocks.threads.DefaultThreadManager"
  			   activation="startup">
      	<configuration>
  	    	<thread-group>
  	        	<name>default</name>
  	        	<priority>5</priority>
  	        	<is-daemon>false</is-daemon>
  	        	<max-threads>40</max-threads>
  	        	<min-threads>20</min-threads>
  	        	<min-spare-threads>20</min-spare-threads>
  	      	</thread-group>
        	</configuration>
  	</component>
  
  	<component name="connection-manager"
  			   class="org.apache.avalon.cornerstone.blocks.connection.DefaultConnectionManager"
  			   activation="startup">
  
  	</component>
  
          <component name="connection-handler-factory"
                             class="tutorial.SimpleConnectionHandlerFactory"
                             activation="startup">
  
  	</component>
  
  	<component name="socket-manager"
  			   class="org.apache.avalon.cornerstone.blocks.sockets.DefaultSocketManager"
  			   activation="startup">
  		<configuration>
  			<server-sockets>
          		<factory name="plain" class="org.apache.avalon.cornerstone.blocks.sockets.DefaultServerSocketFactory"/>
  			</server-sockets>
  
  			<client-sockets>
  			</client-sockets>
  		</configuration>
  	</component>
  
  	<component name="simple-web-server"
  			   class="tutorial.SimpleWebServerComponent"
  			   activation="startup">
  		<configuration>
  			<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
  			<!-- Add and configure a HTTP listener on the given port             -->
  			<!-- The default port = 80                                           -->
  			<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
  			<http-listener port="9080"/>
  		</configuration>
  	</component>
  
  </container>
  
  
  
  1.1                  avalon/merlin/platform/tutorials/simple-web/maven.xml
  
  Index: maven.xml
  ===================================================================
  <project default="jar:jar" xmlns:maven="jelly:maven" xmlns:j="jelly:core" xmlns:util="jelly:util">
  
      <preGoal name="java:compile">
          <attainGoal name="avalon:meta"/>
      </preGoal>
      
  </project>
  
  
  
  1.1                  avalon/merlin/platform/tutorials/simple-web/project.properties
  
  Index: project.properties
  ===================================================================
  #
  # Banner background and foreground colors.
  #
  
  maven.ui.banner.background=#fff
  maven.ui.banner.foreground=#000
  #maven.xdoc.jsl=file:/${basedir}/../site/etc/site.jsl
  #maven.javadoc.stylesheet=${basedir}/../site/etc/stylesheet.css
  #maven.license.licenseFile=${basedir}/../site/etc/LICENSE.txt
  
  #maven.checkstyle.format=avalon
  #pom.organization.identifier = ASF
  #pom.specificationVersion = 1.0
  
  #
  # Declaration of the remote links to assign on javadoc generation.
  # Link declarations can be overriden in the user's build.properties file.
  #
  #sun.j2se.link=http://java.sun.com/j2se/1.4/docs/api/
  #avalon.framework.link=http://avalon.apache.org/framework/api/
  #avalon.logkit.link=http://avalon.apache.org/logkit/api/
  #excalibur.thread.link=http://avalon.apache.org/excalibur/thread/api/
  #excalibur.event.link=http://avalon.apache.org/excalibur/event/api/
  
  #maven.javadoc.links = ${sun.j2se.link},${avalon.logkit.link},${avalon.framework.link},${excalibur.thread.link},${excalibur.event.link}
  #maven.javadoc.links = ${sun.j2se.link},${avalon.framework.link}
  
  
  1.1                  avalon/merlin/platform/tutorials/simple-web/project.xml
  
  Index: project.xml
  ===================================================================
  <?xml version="1.0" encoding="ISO-8859-1"?>
  
  <project>
  
      <extend>${basedir}/../project.xml</extend>
      <groupId>merlin-tutorial</groupId>
      <id>simple-web-server</id>
      
      <!-- a short but descriptive name for the project -->
      <name>Merlin Simple Web Server Tutorials</name>
      <package>tutorial</package>
      <currentVersion>1.0</currentVersion>
          
      <!-- more info about the project -->
      <inceptionYear>2003</inceptionYear>
      <description>
          A merlin component that demonstrates a simple web server based upon
          cornerstone and excalibur components.
      </description>
      <shortDescription>
          A simple web server demonstration for merlin using cornerstone.
      </shortDescription>
  
      <dependencies>
      
  	    <dependency>
  	      <groupId>avalon-framework</groupId>
  	      <artifactId>avalon-framework-api</artifactId>
  	      <version>4.1.5</version>
  	    </dependency>
  
  	    <dependency>
  	      <groupId>cornerstone-sockets</groupId>
  	      <artifactId>cornerstone-sockets-api</artifactId>
  	      <version>1.0</version>
  	    </dependency>
  	    
  	    <dependency>
  	      <groupId>cornerstone-connection</groupId>
  	      <artifactId>cornerstone-connection-api</artifactId>
  	      <version>1.0</version>
  	    </dependency>
  	    
      </dependencies>
          
  </project>
  
  
  
  1.1                  avalon/merlin/platform/tutorials/simple-web/src/java/tutorial/MalformedRequestException.java
  
  Index: MalformedRequestException.java
  ===================================================================
  /*
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
   4. The names "Jakarta", "Apache Avalon", "Avalon Framework" and
      "Apache Software Foundation"  must not be used to endorse or promote
      products derived  from this  software without  prior written
      permission. For written permission, please contact apache@apache.org.
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation. For more  information on the
   Apache Software Foundation, please see <http://www.apache.org/>.
   */
  package tutorial;
  
  /**
   * @author <a href="mailto:timothy.bennett@gxs.com">Timothy Bennett</a>
   */
  public class MalformedRequestException
      extends Exception {
  
    /**
     *
     */
    public MalformedRequestException() {
      super();
    }
  
    /**
     * @param s
     */
    public MalformedRequestException(String s) {
      super(s);
    }
  
    /**
     * @param t
     */
    public MalformedRequestException(Throwable t) {
      super(t);
    }
  
    /**
     * @param s
     * @param t
     */
    public MalformedRequestException(String s, Throwable t) {
      super(s, t);
    }
  
  }
  
  
  
  1.1                  avalon/merlin/platform/tutorials/simple-web/src/java/tutorial/Reply.java
  
  Index: Reply.java
  ===================================================================
  /*
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
   4. The names "Jakarta", "Apache Avalon", "Avalon Framework" and
      "Apache Software Foundation"  must not be used to endorse or promote
      products derived  from this  software without  prior written
      permission. For written permission, please contact apache@apache.org.
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation. For more  information on the
   Apache Software Foundation, please see <http://www.apache.org/>.
   */
  package tutorial;
  
  import java.io.DataOutputStream;
  import java.io.IOException;
  import java.io.OutputStream;
  import java.util.Date;
  
  /**
   * Static-only class to send a simple HTTP reply.
   *
   * @author <a href="mailto:timothy.bennett@gxs.com">Timothy Bennett</a>
   */
  public class Reply {
    /**
     * Definition of a carriage-return/line-feed entity.
     */
    public final static String CRLF = "\r\n";
    /**
     * The HTTP RFC specification version supported by this web server.
     */
    public final static String HTTP_VERSION = "HTTP/1.0";
    /**
     * The HTTP RFC specification version supported by this web server.
     */
    public final static String WEB_SERVER_NAME = "Merlin Simple Server/1.0";
    /**
     * HTTP 200 OK
     */
    public final static String HTTP_200 = HTTP_VERSION + " 200 OK" + CRLF;
    /**
     * HTTP 400 Bad Request
     */
    public final static String HTTP_400 = HTTP_VERSION + " 400 Bad Request" +
        CRLF;
    /**
     * HTTP 403 Forbidden
     */
    public final static String HTTP_403 = HTTP_VERSION + " 404 Forbidden" + CRLF;
    /**
     * HTTP 404 Not Found
     */
    public final static String HTTP_404 = HTTP_VERSION + " 404 Not Found" + CRLF;
    /**
     * HTTP 405 Method Not Allowed
     */
    public final static String HTTP_405 = HTTP_VERSION +
        " 405 Method Not Allowed" + CRLF;
  
    /**
     * Private constructor to enforce static-only class.
     */
    private Reply() {
    }
  
    /**
     *
     * @param os
     * @param type
     * @param msg
     * @throws IOException
     */
    public static void sendHttpReply(OutputStream os, String type, String msg) throws
        IOException {
  
      DataOutputStream dos = new DataOutputStream(os);
      dos.writeBytes(type);
      dos.writeBytes("Connection: close" + CRLF);
      dos.writeBytes("Server: " + WEB_SERVER_NAME + CRLF);
      dos.writeBytes("Date: " + RfcDateFormat.format(new Date()) + CRLF);
      dos.writeBytes("Content-Type: text/html; charset=iso-8859-1" + CRLF);
      //dos.writeBytes("Content-Type: text/html" + CRLF);
      dos.writeBytes("Content-Length: " + msg.length() + CRLF);
      if (type.equals(HTTP_405)) {
        dos.writeBytes("Allow: GET" + CRLF);
      }
      dos.writeBytes(CRLF);
  
      String s = new String("<html><body><h1>" + msg + "</h1></body></html>");
      //dos.writeBytes(s);
      dos.writeUTF(s);
      dos.flush();
      dos.close();
    }
  }
  
  
  
  1.1                  avalon/merlin/platform/tutorials/simple-web/src/java/tutorial/Request.java
  
  Index: Request.java
  ===================================================================
  /*
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
   4. The names "Jakarta", "Apache Avalon", "Avalon Framework" and
      "Apache Software Foundation"  must not be used to endorse or promote
      products derived  from this  software without  prior written
      permission. For written permission, please contact apache@apache.org.
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation. For more  information on the
   Apache Software Foundation, please see <http://www.apache.org/>.
   */
  package tutorial;
  
  import java.net.URI;
  import java.net.URISyntaxException;
  import java.nio.ByteBuffer;
  import java.nio.CharBuffer;
  import java.nio.charset.Charset;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  
  /**
   * Provides a parser for an inbound HTTP connection.  The parser uses regular
   * expressions to examine the action line and host header line.  All other headers
   * and text are ignored.
   *
   * @author <a href="mailto:timothy.bennett@gxs.com">Timothy Bennett</a>
   */
  public class Request {
  
    static class Action {
      private String m_name;
      static final Action GET = new Action("GET");
      static final Action POST = new Action("POST");
      static final Action PUT = new Action("PUT");
      static final Action HEAD = new Action("HEAD");
  
      private Action(String name) {
        m_name = name;
      }
  
      public String toString() {
        return m_name;
      }
  
      static Action parse(String s) throws IllegalArgumentException {
        if (s.equals("GET")) {
          return GET;
        }
        if (s.equals("POST")) {
          return POST;
        }
        if (s.equals("PUT")) {
          return PUT;
        }
        if (s.equals("HEAD")) {
          return HEAD;
        }
        throw new IllegalArgumentException(s);
      }
    }
  
    private Action m_action;
    private String m_version;
    private URI m_uri;
  
    private Request(Action action, String version, URI uri) {
      setAction(action);
      setVersion(version);
      setUri(uri);
    }
  
    private static Charset ascii = Charset.forName("US-ASCII");
  
    private static Pattern requestPattern = Pattern.compile(
        "\\A([A-Z]+) +([^ ]+) +HTTP/([0-9\\.]+)$"
        + ".*^Host: ([^ ]+)$.*\r\n\r\n", Pattern.MULTILINE | Pattern.DOTALL);
  
    public static Request parse(ByteBuffer bb) throws MalformedRequestException {
      CharBuffer cb = ascii.decode(bb);
  
      Matcher m = requestPattern.matcher(cb);
      if (!m.matches()) {
        throw new MalformedRequestException();
      }
  
      Action a;
      try {
        a = Action.parse(m.group(1));
      }
      catch (IllegalArgumentException e) {
        throw new MalformedRequestException(e);
      }
  
      URI u;
      try {
        u = new URI("http://" + m.group(4) + m.group(2));
      }
      catch (URISyntaxException e) {
        throw new MalformedRequestException(e);
      }
  
      return new Request(a, m.group(3), u);
    }
  
    public Action getAction() {
      return m_action;
    }
  
    public String getVersion() {
      return m_version;
    }
  
    public URI getUri() {
      return m_uri;
    }
  
    public boolean isGet() {
      if (m_action.toString().equals("GET")) {
        return true;
      }
      else {
        return false;
      }
    }
  
    private void setAction(Action action) {
      m_action = action;
    }
  
    private void setVersion(String version) {
      m_version = version;
    }
  
    private void setUri(URI uri) {
      m_uri = uri;
    }
  }
  
  
  
  1.1                  avalon/merlin/platform/tutorials/simple-web/src/java/tutorial/RfcDateFormat.java
  
  Index: RfcDateFormat.java
  ===================================================================
  /*
   * RfcDateFormat.java
   *
   */
  
  package tutorial;
  
  import java.util.Date;
  
  /**
   * Alternative RFC 1123 data formatter.  SimpleDataFormat class has thread-safe
   * issues as documented by Sun.  This formatter is based on code provided by
   * Tim Kientzle on the Tomcat list-serv and made available for free public use.
   * @see http://marc.theaimsgroup.com/?l=tomcat-dev&m=97146648030873&w=2
   * @author  Tim Kientzle
   */
  public class RfcDateFormat {
  
      /**
       * Enumeration of the days of the week.
       */
      private static final String[] WEEKDAYS =
          {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
      /**
       * Enumeration of the months of the year.
       */
      private static final String[] MONTHS =
          {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  
      /**
       * Formats a date object according to RFC 1123.
       * <p>
       * An example formatted date would appear as "Sun, 06 Nov 1994 08:49:37 GMT"
       *
       * @param date the date to format
       * @return the given date formatting according to RFC 1123
       */
      public static String format(Date date) {
  
          // Compute day number, seconds since beginning of day
          long s = date.getTime();;
          if (s >= 0) {
              // seconds since 1 Jan 1970
              s /= 1000;
          } else {
              // floor(sec/1000)
              s = (s - 999) / 1000;
          }
  
          int dn = (int) (s / 86400);
          s %= 86400;  // positive seconds since beginning of day
          if (s < 0) {
              s += 86400;
              dn--;
          }
          dn += 1969 * 365 + 492 - 19 + 4; // days since "1 Jan, year 1"
  
          // Convert days since 1 Jan, year 1 to year/yearday
          int y = 400 * (dn / 146097) + 1;
          int d = dn % 146097;
          if (d == 146096) {
              // Last year of 400 is long
              y += 399;
              d = 365;
          } else {
              y += 100 * (d / 36524);
              d %= 36524;
              y += 4 * (d / 1461);
              d %= 1461;
              if (d == 1460) {
                  // Last year out of 4 is long
                  y += 3;
                  d = 365;
              } else {
                  y += d / 365;
                  d %= 365;
              }
          }
  
          boolean isleap = ((y % 4 == 0) && !(y % 100 == 0)) || (y % 400 == 0);
  
          // Compute month/monthday from year/yearday
          if (!isleap && (d >= 59)) {
              // Skip non-existent Feb 29
              d++;
          }
          if (d >= 60) {
              // Skip non-existent Feb 30
              d++;
          }
          int mon = ((d % 214) / 61) * 2 + ((d % 214) % 61) / 31;
          if (d > 213) {
              mon += 7;
          }
          d = ((d % 214) % 61) % 31 + 1;
  
      // Convert second to hour/min/sec
  	int m = (int) (s / 60);
      int h = m / 60;
      m %= 60;
      s %= 60;
  
      // Day of week, 0==Sun
  	int w = (dn + 1) % 7;
  
  	/* RFC 1123 date string: "Sun, 06 Nov 1994 08:49:37 GMT" */
  	StringBuffer buff = new StringBuffer(32);
  	buff.append(WEEKDAYS[w]);
  	buff.append(", ");
  	buff.append((char) (d / 10 + '0'));
  	buff.append((char) (d % 10 + '0'));
  	buff.append(' ');
  	buff.append(MONTHS[mon]);
  	buff.append(' ');
  	buff.append(y);
  	buff.append(' ');
  	buff.append((char) (h / 10 + '0'));
  	buff.append((char) (h % 10 + '0'));
  	buff.append(':');
  	buff.append((char) (m / 10 + '0'));
  	buff.append((char) (m % 10 + '0'));
  	buff.append(':');
  	buff.append((char) (s / 10 + '0'));
  	buff.append((char) (s % 10 + '0'));
  	buff.append(" GMT");
  	return buff.toString();
      }
  }
  
  
  
  1.1                  avalon/merlin/platform/tutorials/simple-web/src/java/tutorial/SimpleConnectionHandler.java
  
  Index: SimpleConnectionHandler.java
  ===================================================================
  /*
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
   4. The names "Jakarta", "Apache Avalon", "Avalon Framework" and
      "Apache Software Foundation"  must not be used to endorse or promote
      products derived  from this  software without  prior written
      permission. For written permission, please contact apache@apache.org.
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation. For more  information on the
   Apache Software Foundation, please see <http://www.apache.org/>.
   */
  package tutorial;
  
  import java.io.ByteArrayOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.net.ProtocolException;
  import java.net.Socket;
  import java.nio.ByteBuffer;
  
  import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;
  import org.apache.avalon.framework.logger.Logger;
  
  /**
   * Simple connection handler for our web server.  It conforms to HTTP/1.0 only.
   * This handler will perform the following tasks:
   * <ul>
   *  <li>Parse the request
   *  <li>Build the reply
   *  <li>Send the reply
   * </ul>
   *
   * @author <a href="mailto:timothy.bennett@gxs.com">Timothy Bennett</a>
   */
  public class SimpleConnectionHandler
      implements ConnectionHandler {
    /**
     * Internal reference to the logging channel supplied by the container.
     */
    private Logger m_logger;
  
    /**
     * Processes connections as they occur.
     *
     * @param socket the socket connection
     * @throws IOException if an error reading from the socket occurs
     * @throws ProtocolException if an error handling the connection occurs
     *
     * @see org.apache.avalon.cornerstone.services.connection.ConnectionHandler#handleConnection(java.net.Socket)
     */
    public void handleConnection(Socket socket) throws IOException,
        ProtocolException {
      Request req;
  
      // who has connected to us?
      String remoteHost = socket.getInetAddress().getHostName();
      String remoteIP = socket.getInetAddress().getHostAddress();
      getLogger().info("Connection received on port " + socket.getLocalPort()
                       + " from " + remoteHost + " (" + remoteIP + ")");
  
      // get a request object...
      InputStream input = socket.getInputStream();
      ByteArrayOutputStream output = new ByteArrayOutputStream();
      byte[] bytes = new byte[1024];
      int count = input.read(bytes);
      while (count > -1) {
        output.write(bytes, 0, count);
        if (input.available() == 0) {
          break;
        }
        count = input.read(bytes);
      }
      output.flush();
      output.close();
  
      getLogger().debug("Preparing byte buffer...");
      ByteBuffer bb = ByteBuffer.allocate(output.size());
      bb.put(output.toByteArray());
      bb.flip();
      getLogger().debug("Byte buffer prepared");
      try {
        getLogger().debug("Parsing request...");
        req = Request.parse(bb);
      }
      catch (MalformedRequestException e) {
        getLogger().error(e.getMessage(), e);
        throw new ProtocolException(e.getMessage());
      }
  
      // Handle the request -- only accept HTTP GET
      if (!req.isGet()) {
        getLogger().debug("Sending HTTP 405...");
        Reply.sendHttpReply(socket.getOutputStream(), Reply.HTTP_405,
                            "This server only accepts GET");
      }
      else {
        getLogger().debug("Sending HTTP 200...");
        Reply.sendHttpReply(socket.getOutputStream(), Reply.HTTP_200,
                            "Hello, World!");
      }
    }
  
    /**
     * Sets the container-supplied logger.
     */
    public void setLogger(Logger logger) {
      m_logger = logger;
    }
  
    /**
     * Return the logging channel assigned to us by the container.
     * @return the logging channel
     */
    private Logger getLogger() {
      return m_logger;
    }
  }
  
  
  
  1.1                  avalon/merlin/platform/tutorials/simple-web/src/java/tutorial/SimpleConnectionHandlerFactory.java
  
  Index: SimpleConnectionHandlerFactory.java
  ===================================================================
  /*
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
   4. The names "Jakarta", "Apache Avalon", "Avalon Framework" and
      "Apache Software Foundation"  must not be used to endorse or promote
      products derived  from this  software without  prior written
      permission. For written permission, please contact apache@apache.org.
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation. For more  information on the
   Apache Software Foundation, please see <http://www.apache.org/>.
   */
  package tutorial;
  
  import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;
  import org.apache.avalon.cornerstone.services.connection.
      ConnectionHandlerFactory;
  import org.apache.avalon.framework.logger.Logger;
  import org.apache.avalon.framework.logger.LogEnabled;
  
  /**
   * A simple factory for creating instances of <code>SimpleConnectionHandler</code>.
   * We're not doing anything fancy (or safe) here like pooling connections or queuing
   * if we are busy.
   *
   * @author <a href="mailto:timothy.bennett@gxs.com">Timothy Bennett</a>
   * @avalon.component version="1.0" name="connection-handler-factory" lifestyle="singleton"
   * @avalon.service type="org.apache.avalon.cornerstone.services.connection.ConnectionHandlerFactory"
   */
  public class SimpleConnectionHandlerFactory
      implements ConnectionHandlerFactory, LogEnabled {
    /**
     * Internal reference to the logging channel supplied by the container.
     */
    private Logger m_logger;
  
    /**
     * Constructs an instance of a <code>SimpleConnectionHandler</code> that will
     * handle an incoming web request.
     *
     * @see org.apache.avalon.cornerstone.services.connection.ConnectionHandlerFactory#createConnectionHandler()
     */
    public ConnectionHandler createConnectionHandler() throws Exception {
      SimpleConnectionHandler handler = new SimpleConnectionHandler();
      handler.setLogger(m_logger);
      return handler;
    }
  
    /**
     * Does nothing since we aren't doing anything fancy here...
     *
     * @see org.apache.avalon.cornerstone.services.connection.ConnectionHandlerFactory#releaseConnectionHandler(org.apache.avalon.cornerstone.services.connection.ConnectionHandler)
     */
    public void releaseConnectionHandler(ConnectionHandler handler) {
    }
  
    /**
     * Sets the container-supplied logger.
     */
    public void enableLogging(Logger logger) {
      m_logger = logger;
    }
  }
  
  
  
  1.1                  avalon/merlin/platform/tutorials/simple-web/src/java/tutorial/SimpleWebServerComponent.java
  
  Index: SimpleWebServerComponent.java
  ===================================================================
  /*
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
   4. The names "Jakarta", "Apache Avalon", "Avalon Framework" and
      "Apache Software Foundation"  must not be used to endorse or promote
      products derived  from this  software without  prior written
      permission. For written permission, please contact apache@apache.org.
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation. For more  information on the
   Apache Software Foundation, please see <http://www.apache.org/>.
   */
  
  package tutorial;
  
  import java.net.ServerSocket;
  
  import org.apache.avalon.cornerstone.services.connection.
      ConnectionHandlerFactory;
  import org.apache.avalon.cornerstone.services.connection.ConnectionManager;
  import org.apache.avalon.cornerstone.services.sockets.ServerSocketFactory;
  import org.apache.avalon.cornerstone.services.sockets.SocketManager;
  import org.apache.avalon.framework.activity.Disposable;
  import org.apache.avalon.framework.activity.Executable;
  import org.apache.avalon.framework.configuration.Configurable;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.logger.LogEnabled;
  import org.apache.avalon.framework.logger.Logger;
  import org.apache.avalon.framework.service.ServiceException;
  import org.apache.avalon.framework.service.ServiceManager;
  import org.apache.avalon.framework.service.Serviceable;
  
  /**
   * A tutorial that demonstrates a simple web server component for merlin that
   * uses the <code>SocketManager</code> and <code>ConnectionManager</code>
   * components in the cornerstone and excalibur component packages.
   *
   * @author <a href="mailto:timothy.bennett@gxs.com">Timothy Bennett</a>
   *
   * @avalon.component version="1.0" name="simple-web-server"
   */
  public class SimpleWebServerComponent
      implements LogEnabled, Serviceable, Configurable, Executable, Disposable {
    /**
     * Internal reference to the logging channel supplied by the container.
     */
    private Logger m_logger;
    /**
     * Internal reference to the socket manager supplied by the container.
     */
    private SocketManager m_socketManager;
    /**
     * Internal reference to the connection manager supplied by the container.
     */
    private ConnectionManager m_connectionManager;
    /**
     * Internal reference to connection handler factory supplied by container
     */
    private ConnectionHandlerFactory m_connectionHandlerFactory;
    /**
     * Internal reference to the web server's listening port supplied
     * by the conponent configuration.  Defaults to 80.
     */
    private int m_port;
    /**
     * Alias for the name of our HTTP connection handler.
     */
    private final static String HTTP_LISTENER = "http-listener";
  
    /**
     * Supply of a logging channel by the container.
     *
     * @param logger the logging channel for this component
     *
     * @see org.apache.avalon.framework.logger.LogEnabled#enableLogging(org.apache.avalon.framework.logger.Logger)
     */
    public void enableLogging(Logger logger) {
      m_logger = logger;
      getLogger().info("logging");
    }
  
    /**
     * Servicing of the component by the container during which service
     * dependencies declared under the component can be resolved using the
     * supplied service manager.
     *
     * @param manager the service manager
         * @throws ServiceException if an failure occurs while servicing the component
     *
     * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
     *
     * @avalon.dependency type="org.apache.avalon.cornerstone.services.sockets.SocketManager:1.0" key="socket-manager"
     * @avalon.dependency type="org.apache.avalon.cornerstone.services.connection.ConnectionManager:1.0" key="connection-manager"
     * @avalon.dependency type="org.apache.avalon.cornerstone.services.connection.ConnectionHandlerFactory:1.0" key="connection-handler-factory"
     */
    public void service(ServiceManager manager) throws ServiceException {
      m_socketManager = (SocketManager) manager.lookup("socket-manager");
      m_connectionManager = (ConnectionManager) manager.lookup(
          "connection-manager");
      m_connectionHandlerFactory = (ConnectionHandlerFactory) manager.lookup("connection-handler-factory");
    }
  
    /**
     * Configuration of the component by the container.
     *
     * TODO: Describe the configuration of the component.
     *
     * @param config the component configuration
     * @throws ConfigurationException if a configuration error occurs
     *
     * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
     */
    public void configure(Configuration config) throws ConfigurationException {
      getLogger().info("Configuring...");
  
      // Add an HTTP socket listener?
      Configuration httpConfig = config.getChild("http-listener", true);
      if (httpConfig == null) {
        throw new ConfigurationException("port attribute not found!");
      }
      else {
        m_port = httpConfig.getAttributeAsInteger("port", 80);
      }
    }
  
    /**
     * Component execution trigger by the container following
     * completion of the initialization stage.
     *
     * @see org.apache.avalon.framework.activity.Executable#execute()
     */
    public void execute() throws Exception {
      // Use the Cornerstone SocketManager to give us a factory object for creating
      // a plain ole server socket
      ServerSocketFactory ssf = m_socketManager.getServerSocketFactory("plain");
  
      // Use that factory to create a server socket
      ServerSocket serverSocket = ssf.createServerSocket(m_port);
  
      // attach the server socket to our connection manager
      m_connectionManager.connect(HTTP_LISTENER, serverSocket, m_connectionHandlerFactory);
  
      // we've started!
      getLogger().info("Started HTTP listener socket on port {" + m_port + "}");
    }
  
    /**
     * Component disposal trigger by the container during which
     * the component will release consumed resources.
     *
     * @see org.apache.avalon.framework.activity.Disposable#dispose()
     */
    public void dispose() {
      try {
        // forcefully tear down all handlers...
        m_connectionManager.disconnect(HTTP_LISTENER, true);
      }
      catch (Exception e) {
        getLogger().error("Unexpected error while shutting down HTTP listener", e);
      }
      m_connectionManager = null;
      m_socketManager = null;
    }
  
    /**
     * Return the logging channel assigned to us by the container.
     * @return the logging channel
     */
    private Logger getLogger() {
      return m_logger;
    }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: cvs-unsubscribe@avalon.apache.org
For additional commands, e-mail: cvs-help@avalon.apache.org