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