You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by tr...@apache.org on 2007/10/23 04:29:48 UTC
svn commit: r587364 [4/7] - in /mina/sandbox/asyncweb: ./ assembly/
assembly/src/ assembly/src/main/ assembly/src/main/descriptor/ core/
core/src/ core/src/main/ core/src/main/java/ core/src/main/java/org/
core/src/main/java/org/safehaus/ core/src/main...
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/AbstractHttpServiceContext.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/AbstractHttpServiceContext.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/AbstractHttpServiceContext.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/AbstractHttpServiceContext.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.context;
+
+import java.net.InetSocketAddress;
+
+import org.safehaus.asyncweb.common.DefaultHttpResponse;
+import org.safehaus.asyncweb.common.HttpRequest;
+import org.safehaus.asyncweb.common.HttpResponse;
+import org.safehaus.asyncweb.common.HttpResponseStatus;
+import org.safehaus.asyncweb.common.MutableHttpResponse;
+import org.safehaus.asyncweb.service.HttpServiceContext;
+import org.safehaus.asyncweb.service.HttpSession;
+import org.safehaus.asyncweb.service.ServiceContainer;
+import org.safehaus.asyncweb.util.HttpHeaderConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A default implementation of {@link HttpServiceContext}.
+ *
+ * @author trustin
+ * @version $Rev:167 $, $Date:2006-11-15 11:10:05 +0000 (ì, 15 11ì 2006) $
+ */
+public abstract class AbstractHttpServiceContext implements HttpServiceContext {
+
+ private final Logger log = LoggerFactory.getLogger(AbstractHttpServiceContext.class);
+ private final InetSocketAddress remoteAddress;
+ private final HttpRequest request;
+ private HttpResponse committedResponse;
+ private HttpSession session;
+ private boolean createdSession;
+ private final ServiceContainer container;
+
+ public AbstractHttpServiceContext(
+ InetSocketAddress remoteAddress, HttpRequest request, ServiceContainer container) {
+ if (remoteAddress == null) {
+ throw new NullPointerException("remoteAddress");
+ }
+ if (request == null) {
+ throw new NullPointerException("request");
+ }
+ if (container == null) {
+ throw new NullPointerException("container");
+ }
+
+ this.remoteAddress = remoteAddress;
+ this.request = request;
+ this.container = container;
+ this.session = container.getSessionAccessor().getSession(this, false);
+ }
+
+ public synchronized boolean isResponseCommitted() {
+ return committedResponse != null;
+ }
+
+ /**
+ * Commits a <code>HttpResponse</code> to this <code>Request</code>.
+ *
+ * @param response The response to commit
+ * @return <code>true</code> iff the response was committed
+ */
+ public boolean commitResponse(HttpResponse response) {
+ synchronized (this) {
+ if (isResponseCommitted()) {
+ if (log.isDebugEnabled()) {
+ log.info("Request already comitted to a response. Disposing response");
+ }
+ return false;
+ }
+
+ committedResponse = response;
+ }
+
+ // Add the session identifier if the session was newly created.
+ if (createdSession) {
+ container.getSessionAccessor().addSessionIdentifier(this, (MutableHttpResponse) response);
+ }
+
+ // Only parsed requests can be formatted.
+ if (getRequest().getMethod() != null) {
+ container.getErrorResponseFormatter().formatResponse(getRequest(), (MutableHttpResponse) response);
+ }
+
+ if (container.isSendServerHeader()) {
+ ((MutableHttpResponse) response).setHeader(HttpHeaderConstants.KEY_SERVER, "AsyncWeb");
+ }
+
+ // Normalize the response.
+ ((MutableHttpResponse) response).normalize(getRequest());
+
+ // Override connection header if needed.
+ if (!container.getKeepAliveStrategy().keepAlive(this, response)) {
+ ((MutableHttpResponse) response).setHeader(
+ HttpHeaderConstants.KEY_CONNECTION, HttpHeaderConstants.VALUE_CLOSE);
+ }
+
+ boolean requiresClosure = !HttpHeaderConstants.VALUE_KEEP_ALIVE.equalsIgnoreCase(
+ response.getHeader(HttpHeaderConstants.KEY_CONNECTION));
+
+ if (requiresClosure && log.isDebugEnabled()) {
+ log.debug("Response status: " + response.getStatus());
+ log.debug("Keep-alive strategy requires closure of " + getRemoteAddress());
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("Committing a response:");
+ log.debug("Status: " + response.getStatus() + ' ' + response.getStatusReasonPhrase());
+ log.debug("Headers: " + response.getHeaders());
+ }
+
+ doWrite(requiresClosure);
+
+ return true;
+ }
+
+ public boolean commitResponse(HttpResponseStatus status) {
+ MutableHttpResponse response = new DefaultHttpResponse();
+ response.setStatus(status);
+ return commitResponse(response);
+ }
+
+ public synchronized HttpResponse getCommittedResponse() {
+ return committedResponse;
+ }
+
+ public InetSocketAddress getRemoteAddress() {
+ return remoteAddress;
+ }
+
+ public HttpRequest getRequest() {
+ return request;
+ }
+
+ public HttpSession getSession() {
+ return getSession(true);
+ }
+
+ public synchronized HttpSession getSession(boolean create) {
+ if (session != null && !session.isValid()) {
+ session = null;
+ }
+ if (session == null) {
+ session = container.getSessionAccessor().getSession(this, create);
+ if (create) {
+ createdSession = true;
+ }
+ }
+
+ return session;
+ }
+
+ protected abstract void doWrite(boolean requiresClosure);
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/AbstractHttpServiceContext.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/AbstractHttpServiceContext.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/BasicKeepAliveStrategy.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/BasicKeepAliveStrategy.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/BasicKeepAliveStrategy.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/BasicKeepAliveStrategy.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.context;
+
+import org.safehaus.asyncweb.common.HttpResponse;
+import org.safehaus.asyncweb.service.HttpServiceContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Defines common sensible behaviour for the rules under which a
+ * connection should be kept alive.
+ * <code>BasicKeepAliveStrategy</code> will signal that a connection
+ * should be closed iff:
+ * <ul>
+ * <li>The request is <i>committed</i></li>
+ * <li>The status of a response forces the connection to be closed</li>
+ * <li>The request does not want keep-alives</li>
+ * </ul>
+ * Implementations should override <code></code> to provide additional
+ * constraints
+ *
+ * @author irvingd
+ *
+ */
+public class BasicKeepAliveStrategy implements KeepAliveStrategy {
+
+ private static final Logger LOG = LoggerFactory.getLogger(BasicKeepAliveStrategy.class);
+
+ /**
+ * Determines whether a connection should be kept alive based
+ * on a response.
+ * This method returns true iff either:
+ * <ul>
+ * <li>The request is not committed</li>
+ * </u>
+ * or (in order):
+ * <ul>
+ * <li>The status of a response does not force closure</li>
+ * <li>The request indicates that it wants the connection to remain
+ * open</li>
+ * <li><code>doIsKeepAlive</code> returns true</li>
+ * </ul>
+ *
+ * @param response The response to examine
+ * @return <code>true</code> iff a connection should be kept alive
+ */
+ public final boolean keepAlive(HttpServiceContext context, HttpResponse response) {
+ boolean isKeepAlive;
+ if (!context.isResponseCommitted()) {
+ isKeepAlive = true;
+ } else {
+ isKeepAlive = !response.getStatus().forcesConnectionClosure() &&
+ context.getRequest().isKeepAlive() &&
+ doIsKeepAlive(context, response);
+ if (!isKeepAlive && LOG.isDebugEnabled() &&
+ response.getStatus().forcesConnectionClosure()) {
+ LOG.debug("Response status forces closure: " + response.getStatus());
+ }
+ }
+ return isKeepAlive;
+ }
+
+ /**
+ * Simply returns <code>true</code> by default.
+ * Implementations should override this method to provide any
+ * additional keep-alive conditions
+ *
+ * @param context The context to check
+ * @param response The request to check
+ * @return <code>true</code> if the connection should
+ * be kept alive
+ */
+ @SuppressWarnings("unused")
+ protected boolean doIsKeepAlive(HttpServiceContext context, HttpResponse response) {
+ return true;
+ }
+
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/BasicKeepAliveStrategy.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/BasicKeepAliveStrategy.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/CounterKeepAliveStrategy.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/CounterKeepAliveStrategy.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/CounterKeepAliveStrategy.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/CounterKeepAliveStrategy.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.context;
+
+import org.safehaus.asyncweb.common.HttpResponse;
+import org.safehaus.asyncweb.service.HttpServiceContext;
+
+
+public class CounterKeepAliveStrategy extends BasicKeepAliveStrategy {
+
+ private static final int DEFAULT_KEEP_ALIVES = 100;
+
+ private int maxKeepAlives = DEFAULT_KEEP_ALIVES;
+ private int keptAliveCount;
+
+ /**
+ * @param maxKeepAlives The maximum number of requests for which
+ * a connection should be kept alive
+ */
+ public CounterKeepAliveStrategy(int maxKeepAlives) {
+ this.maxKeepAlives = maxKeepAlives;
+ }
+
+ /**
+ * Determines whether a connection should be "kept alive" based on
+ * the number of requests for which the connection has previously
+ * been kept alive.
+ *
+ * @param response The response to check
+ */
+ protected boolean doIsKeepAlive(HttpServiceContext context, HttpResponse response) {
+ return ++keptAliveCount < maxKeepAlives;
+ }
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/CounterKeepAliveStrategy.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/CounterKeepAliveStrategy.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/KeepAliveStrategy.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/KeepAliveStrategy.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/KeepAliveStrategy.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/KeepAliveStrategy.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.context;
+
+import org.safehaus.asyncweb.common.HttpResponse;
+import org.safehaus.asyncweb.service.HttpServiceContext;
+
+
+/**
+ * Defines a strategy for deciding whether a connection should
+ * remain open after a response has been handled
+ *
+ * @author irvingd
+ *
+ */
+public interface KeepAliveStrategy {
+
+ /**
+ * Determines whether a connection should remain open after a
+ * response has been handled
+ *
+ * @param context The context to check
+ * @param response The response to check
+ * @return <code>true</code> iff a connection should
+ * remain open after processing the specified response
+ */
+ public boolean keepAlive(HttpServiceContext context, HttpResponse response);
+
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/KeepAliveStrategy.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/context/KeepAliveStrategy.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/errorReporting/CSS.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/errorReporting/CSS.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/errorReporting/CSS.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/errorReporting/CSS.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.errorReporting;
+
+import java.io.UnsupportedEncodingException;
+
+import org.apache.mina.common.ByteBuffer;
+
+/**
+ * Manages the stylesheet info used for generated pages
+ *
+ * TODO: Should be moved out to a configuration file when we sort out a
+ * standard resource strategy
+ *
+ * @author irvingd
+ *
+ */
+public class CSS {
+ //525D76
+ private static final String BG = "3300cc";
+
+ private static final String CSS_STRING =
+ "H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#" + BG + ";font-size:22px;} " +
+ "H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#" + BG + ";font-size:16px;} " +
+ "H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#" + BG + ";font-size:14px;} " +
+ "BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} " +
+ "B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#" + BG + ";} " +
+ "P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}" +
+ "A {color : black;}" +
+ "A.name {color : black;}\n" +
+ "TABLE {cellpadding:20;border-color:black;border-width:1px;border-style:solid;border-collapse:collapse}" +
+ "TD {border-width:1px;border-color:black;border-style:solid;font-family:Tahoma,Arial,sans-serif;color:black;font-size:12px;}" +
+ "TH {border-width:1px;border-color:black;border-style:solid;font-family:Tahoma,Arial,sans-serif;background-color:FF99FF;color:black;font-size:12px;}" +
+ "HR {color : #" + BG + ";}";
+
+ private static byte[] BYTES;
+
+ static {
+ try {
+ BYTES = CSS_STRING.getBytes("US-ASCII");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("Must support US-ASCII");
+ }
+ }
+
+ public static void writeTo(ByteBuffer buf) {
+ buf.put(BYTES);
+ }
+
+ public static StringBuilder appendTo(StringBuilder buff) {
+ buff.append(CSS_STRING);
+ return buff;
+ }
+
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/errorReporting/CSS.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/errorReporting/CSS.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/errorReporting/ErrorResponseFormatter.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/errorReporting/ErrorResponseFormatter.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/errorReporting/ErrorResponseFormatter.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/errorReporting/ErrorResponseFormatter.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.errorReporting;
+
+import org.safehaus.asyncweb.common.HttpRequest;
+import org.safehaus.asyncweb.common.MutableHttpResponse;
+
+/**
+ * Formats error responses to include a descriptive body where appropriate
+ *
+ * @author irvingd
+ *
+ */
+public interface ErrorResponseFormatter {
+
+ /**
+ * Applies any appropriate formatting to a <code>Response</code> based on its
+ * response status code
+ *
+ * @param response The response to format
+ */
+ public void formatResponse(HttpRequest request, MutableHttpResponse response);
+
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/errorReporting/ErrorResponseFormatter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/errorReporting/ErrorResponseFormatter.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/errorReporting/StandardResponseFormatter.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/errorReporting/StandardResponseFormatter.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/errorReporting/StandardResponseFormatter.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/errorReporting/StandardResponseFormatter.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.errorReporting;
+
+import java.io.UnsupportedEncodingException;
+
+import org.apache.mina.common.ByteBuffer;
+import org.safehaus.asyncweb.common.HttpRequest;
+import org.safehaus.asyncweb.common.HttpResponseStatus;
+import org.safehaus.asyncweb.common.MutableHttpResponse;
+import org.safehaus.asyncweb.common.HttpResponseStatus.Category;
+import org.safehaus.asyncweb.common.content.ByteBufferContent;
+import org.safehaus.asyncweb.util.StringBundle;
+
+
+public class StandardResponseFormatter implements ErrorResponseFormatter {
+
+ private static final StringBundle bundle
+ = StringBundle.getBundle(StandardResponseFormatter.class.getPackage().getName());
+
+ public void formatResponse(HttpRequest request, MutableHttpResponse response) {
+ if (shouldFormat(response)) {
+ doFormat(request, response);
+ response.addHeader("content-type", "text/html");
+ }
+ }
+
+ private boolean shouldFormat(MutableHttpResponse response) {
+ boolean shouldFormat = false;
+ // FIXME Should be able to handler other content types.
+ if (!(response.getContent() instanceof ByteBufferContent)) {
+ HttpResponseStatus status = response.getStatus();
+ HttpResponseStatus.Category category = response.getStatus().getCategory();
+ shouldFormat = status.allowsMessageBody() &&
+ (category == Category.CLIENT_ERROR ||
+ category == Category.SERVER_ERROR);
+ }
+ return shouldFormat;
+ }
+
+ private void doFormat(HttpRequest request, MutableHttpResponse response) {
+ StringBuilder html = new StringBuilder(1024);
+ html.append("<html><head><title>");
+ html.append("AsyncWeb Server - ");
+ html.append(bundle.getString("errorMessage"));
+ html.append("</title><style><!--");
+ CSS.appendTo(html).append("--></style>");
+ html.append("</head></body>");
+ html.append("<h1>");
+ html.append(bundle.getString("errorTitle"));
+ html.append("</h1>");
+ response.getStatusReasonPhrase();
+ String code = String.valueOf(response.getStatus().getCode());
+ html.append("<h1>");
+ html.append(bundle.getString("statusInfo", code));
+ html.append("</h1>");
+ html.append("<HR size=\"1\" noshade=\"noshade\">");
+
+ html.append("<p><table cellpadding=\"5\">");
+ appendInfo("statusCode", String.valueOf(response.getStatus().getCode()), html);
+ appendInfo("description", getErrorMessage(response), html);
+ appendInfo("requestMethod", request.getMethod().toString(), html);
+ html.append("</table></p>");
+
+ html.append("<HR size=\"1\" noshade=\"noshade\">");
+ html.append("<H2>AsyncWeb Server</H2>");
+
+ ByteBuffer out = ByteBuffer.allocate(html.length());
+
+ // TODO: Need to sort this out when we start dealing with character encodings
+ try {
+ byte[] bytes = html.toString().getBytes("US-ASCII");
+ out.put(bytes);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+
+ out.flip();
+ response.setContent(new ByteBufferContent(out));
+ }
+
+ private void appendInfo(String title, String info, StringBuilder html) {
+ html.append("<tr><th>").append(bundle.getString(title)).append("</th>");
+ html.append("<td>").append(info).append("</td>");
+ }
+
+ private String getErrorMessage(MutableHttpResponse response) {
+ int responseCode = response.getStatus().getCode();
+ String errorMessage = response.getStatusReasonPhrase();
+ if (errorMessage == null) {
+ errorMessage = "";
+ }
+ return bundle.getString("http." + responseCode, errorMessage);
+ }
+
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/errorReporting/StandardResponseFormatter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/errorReporting/StandardResponseFormatter.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/filter/SessionKeepAliveFilter.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/filter/SessionKeepAliveFilter.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/filter/SessionKeepAliveFilter.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/filter/SessionKeepAliveFilter.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.filter;
+
+import org.safehaus.asyncweb.service.HttpServiceContext;
+import org.safehaus.asyncweb.service.HttpServiceFilter;
+import org.safehaus.asyncweb.service.HttpSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A <code>ServiceHandler</code> which causes any existing session associated with
+ * each request it handles to be renewed.
+ * This causes sessions attached to requests to be renewed per-request - even if
+ * the request does not cause session access to occur.<br/>
+ *
+ * This handler does not need to be installed for deployments which do not employ
+ * sessions
+ *
+ * @author irvingd
+ *
+ */
+public class SessionKeepAliveFilter implements HttpServiceFilter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SessionKeepAliveFilter.class);
+
+ /**
+ * Handles the specified request.
+ * The session associated with the current request - if any - is retrieved -
+ * causing its lease to be renewed.
+ */
+ public void handleRequest(NextFilter next, HttpServiceContext context) {
+ HttpSession session = context.getSession(false);
+ if (session != null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Session renewed: " + session.getId());
+ }
+ } else {
+ LOG.debug("No session to renew");
+ }
+ next.invoke();
+ }
+
+ public void start() {
+ // Not interested in startup
+ }
+
+ public void stop() {
+ // Not interested in shutdown
+ }
+
+ /**
+ * Simply moves the response forward in the chain
+ */
+ public void handleResponse(NextFilter next, HttpServiceContext context) {
+ next.invoke();
+ }
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/filter/SessionKeepAliveFilter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/filter/SessionKeepAliveFilter.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/filter/ThreadPoolFilter.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/filter/ThreadPoolFilter.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/filter/ThreadPoolFilter.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/filter/ThreadPoolFilter.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.filter;
+
+import org.safehaus.asyncweb.service.HttpServiceContext;
+import org.safehaus.asyncweb.service.HttpServiceFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import EDU.oswego.cs.dl.util.concurrent.BoundedLinkedQueue;
+import EDU.oswego.cs.dl.util.concurrent.PooledExecutor;
+
+/**
+ * A <code>ServiceHandler</code> which offloads requests and optionally
+ * responses to a thread pool
+ *
+ * @author irvingd
+ * @author trustin
+ * @version $Rev$, $Date$
+ */
+public class ThreadPoolFilter implements HttpServiceFilter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ThreadPoolFilter.class);
+
+ private static final int DEFAULT_MAX_QUEUE_SIZE = 1000;
+ private static final int DEFAULT_MIN_THREADS = 1;
+ private static final int DEFAULT_MAX_THREADS = 10;
+
+ private PooledExecutor pool;
+ private boolean poolResponses;
+ private int maxQueueSize = DEFAULT_MAX_QUEUE_SIZE;
+ private int minThreads = DEFAULT_MIN_THREADS;
+ private int maxThreads = DEFAULT_MAX_THREADS;
+
+ /**
+ * Handles the specified request.
+ * A task is scheduled with our thread pool to
+ * initiate onward filter invocation asyncronously
+ */
+ public void handleRequest(final NextFilter next, HttpServiceContext context) {
+ enqueue(new Runnable() {
+ public void run() {
+ next.invoke();
+ }
+ });
+ }
+
+ /**
+ * Handles the specified response.
+ * If we are configured to offload responses, a task is scheduled
+ * with our thread pool to initiate onward filter invocation
+ * asyncronously
+ */
+ public void handleResponse(final NextFilter next, HttpServiceContext context) {
+ if (poolResponses) {
+ enqueue(new Runnable() {
+ public void run() {
+ next.invoke();
+ }
+ });
+ } else {
+ next.invoke();
+ }
+ }
+
+ /**
+ * Starts this filter - creating and configuring the underlying
+ * thread pool
+ */
+ public void start() {
+ LOG.info("ThreadPoolHandler starting: maxQueueSize=" + maxQueueSize +
+ " minThreads= " + minThreads + " maxThreads= " + maxThreads +
+ " poolResponses=" + poolResponses);
+ pool = new PooledExecutor(new BoundedLinkedQueue(maxQueueSize));
+ pool.setMaximumPoolSize(maxThreads);
+ pool.setMinimumPoolSize(minThreads);
+ pool.runWhenBlocked();
+ }
+
+ public void stop() {
+ // TODO: Clean shut-down
+ }
+
+ /**
+ * Sets the minimum number of threads to be employed
+ *
+ * @param minThreads The minimum number of threads
+ */
+ public void setMinThreads(int minThreads) {
+ this.minThreads = minThreads;
+ }
+
+ /**
+ * Sets the maximum number of threads to be employed
+ *
+ * @param maxThreads The maximum number of threads
+ */
+ public void setMaxThreads(int maxThreads) {
+ this.maxThreads = maxThreads;
+ }
+
+ /**
+ * Sets the maximum number of requests which are queued for
+ * asyncronous execution, before tasks are run on the calling
+ * thread
+ *
+ * @param maxQueueSize The maximum queue size
+ */
+ public void setMaxQueueSize(int maxQueueSize) {
+ this.maxQueueSize = maxQueueSize;
+ }
+
+ private void enqueue(Runnable task) {
+ try {
+ pool.execute(task);
+ } catch (InterruptedException e) {
+ LOG.error("Failed to schedule pool task", e);
+ }
+ }
+
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/filter/ThreadPoolFilter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/filter/ThreadPoolFilter.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/pipeline/RequestPipeline.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/pipeline/RequestPipeline.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/pipeline/RequestPipeline.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/pipeline/RequestPipeline.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.pipeline;
+
+import org.safehaus.asyncweb.service.HttpServiceContext;
+
+public interface RequestPipeline {
+
+ /**
+ * Adds a request to this pipeline.
+ *
+ * @return <code>true</code> iff the pipeline accepts the request
+ */
+ public boolean addRequest(HttpServiceContext context);
+
+ /**
+ * Frees any responses which may now be provided to the client as a result
+ * of the specified response becoming available.
+ * If the associated request has not been previously added to this pipeline,
+ * it joins the pipeline at the back of the queue: All previously added
+ * requests must be responded to before the new request can take its turn<br/>
+ */
+ public void releaseResponse(HttpServiceContext context);
+
+
+ /**
+ * Sets the <code>PipelineListener</code> to be notified when
+ * a request is released from this pipeline
+ *
+ * @param listener The listener
+ */
+ public void setPipelineListener(RequestPipelineListener listener);
+
+ /**
+ * Disposes of any requests still living in the pipeline
+ */
+ public void disposeAll();
+
+ /**
+ * Runs the scheduled command the next time the pipeline is empty.
+ * Run immediately if the pipeline is currently empty;
+ *
+ * @param r The command to run
+ */
+ public void runWhenEmpty(Runnable r);
+
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/pipeline/RequestPipeline.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/pipeline/RequestPipeline.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/pipeline/RequestPipelineListener.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/pipeline/RequestPipelineListener.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/pipeline/RequestPipelineListener.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/pipeline/RequestPipelineListener.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.pipeline;
+
+import org.safehaus.asyncweb.service.HttpServiceContext;
+
+public interface RequestPipelineListener {
+ public void responseReleased(HttpServiceContext context);
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/pipeline/RequestPipelineListener.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/pipeline/RequestPipelineListener.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/pipeline/StandardRequestPipeline.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/pipeline/StandardRequestPipeline.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/pipeline/StandardRequestPipeline.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/pipeline/StandardRequestPipeline.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.pipeline;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.safehaus.asyncweb.common.HttpResponse;
+import org.safehaus.asyncweb.service.HttpServiceContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class StandardRequestPipeline implements RequestPipeline {
+
+ private static final Logger LOG = LoggerFactory.getLogger(StandardRequestPipeline.class);
+
+ private int maxPipelinedRequests;
+ private RequestPipelineListener listener;
+ private Runnable emptyCommand;
+ private Map<HttpServiceContext, HttpResponse> entryMap = new LinkedHashMap<HttpServiceContext, HttpResponse>();
+
+
+ public StandardRequestPipeline(int maxPipelinedRequests) {
+ this.maxPipelinedRequests = maxPipelinedRequests;
+ }
+
+ public boolean addRequest(HttpServiceContext context) {
+ boolean added = false;
+ synchronized (entryMap) {
+ if (entryMap.size() < maxPipelinedRequests) {
+ entryMap.put(context, null);
+ added = true;
+ }
+ }
+ if (added && LOG.isDebugEnabled()) {
+ LOG.debug("Request added to pipeline ok");
+ }
+ return added;
+ }
+
+ public void releaseResponse(HttpServiceContext context) {
+ if (context.getCommittedResponse() == null) {
+ throw new IllegalStateException("response is not committed.");
+ }
+ synchronized (entryMap) {
+ entryMap.put(context, context.getCommittedResponse());
+ releaseRequests();
+ }
+ }
+
+ public void disposeAll() {
+ synchronized (entryMap) {
+ entryMap.clear();
+ }
+ }
+
+ public void runWhenEmpty(Runnable command) {
+ synchronized (entryMap) {
+ if (entryMap.isEmpty()) {
+ command.run();
+ } else {
+ emptyCommand = command;
+ }
+ }
+ }
+
+ /**
+ * Sets the pipeline listener associated with this pipeline
+ *
+ * @param listener The listener
+ */
+ public void setPipelineListener(RequestPipelineListener listener) {
+ this.listener = listener;
+ }
+
+ /**
+ * Releases any requests which can be freed as a result of a request
+ * being freed.
+ * We simply iterate through the list (in insertion order) - freeing
+ * all responses until we arive at one which has not yet been completed
+ */
+ private void releaseRequests() {
+ for (Iterator<Map.Entry<HttpServiceContext, HttpResponse>> iter = entryMap.entrySet().iterator(); iter.hasNext(); ) {
+ Map.Entry<HttpServiceContext, HttpResponse> entry = iter.next();
+ HttpResponse response = entry.getValue();
+ if (response != null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Response freed from pipeline. Notifying");
+ }
+ listener.responseReleased(entry.getKey());
+ iter.remove();
+ } else {
+ break;
+ }
+ }
+ if (emptyCommand != null && entryMap.isEmpty()) {
+ emptyCommand.run();
+ }
+ }
+
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/pipeline/StandardRequestPipeline.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/pipeline/StandardRequestPipeline.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/CompositeResolver.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/CompositeResolver.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/CompositeResolver.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/CompositeResolver.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.resolver;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.safehaus.asyncweb.common.HttpRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A <code>ServiceResolver</code> which applies a list of child
+ * resolvers in turn until a match is made or all children have
+ * been tried
+ *
+ * @author irvingd
+ *
+ */
+public class CompositeResolver implements ServiceResolver {
+
+ private static final Logger LOG = LoggerFactory.getLogger(CompositeResolver.class);
+
+ private List<ServiceResolver> resolvers = new ArrayList<ServiceResolver>();
+
+ /**
+ * Requests all child resolvers to resolve the request until either
+ * a resolution is found, or all child resolvers have been tried.
+ *
+ * @param request The request to resolve
+ * @return The service name, or <code>null</code> if no resolution could
+ * be found
+ */
+ public String resolveService(HttpRequest request) {
+ for (int i=0, size=resolvers.size(); i < size; ++i) {
+ ServiceResolver resolver = resolvers.get(i);
+ String name = resolver.resolveService(request);
+ if (name != null) {
+ return name;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Adds a resolver. Resolvers are applied in the order they are
+ * added
+ *
+ * @param resolver The resolver
+ */
+ public void addResolver(ServiceResolver resolver) {
+ resolvers.add(resolver);
+ LOG.info("Added resolver: " + resolver.getClass());
+ }
+
+ /**
+ * Sets the resolvers employed by this <code>CompositeResolver</code>
+ *
+ * @param resolvers The resolvers
+ */
+ public void setResolvers(List resolvers) {
+ this.resolvers.clear();
+ // Find bad types early
+ for (Iterator iter = resolvers.iterator(); iter.hasNext(); ) {
+ ServiceResolver resolver = (ServiceResolver) iter.next();
+
+ addResolver(resolver);
+ }
+ }
+
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/CompositeResolver.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/CompositeResolver.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/ExactMatchURIServiceResolver.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/ExactMatchURIServiceResolver.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/ExactMatchURIServiceResolver.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/ExactMatchURIServiceResolver.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.resolver;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.safehaus.asyncweb.common.HttpRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A <code>ServiceResolver</code> which maps request URIs to
+ * service names. An exact match is required on a request URI to
+ * a registered URI must be made for a service name to be resolved
+ *
+ * @author irvingd
+ * FIXME Rename to ExactMatchPathServiceResolver
+ */
+public class ExactMatchURIServiceResolver implements ServiceResolver {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ExactMatchURIServiceResolver.class);
+
+ private Map<String, String> serviceMap = new HashMap<String, String>();
+
+ /**
+ * Adds a mapping from a request URI to a service name.
+ * Any existing mapping for the same URI is overwritten.
+ *
+ * @param uri The URI
+ * @param serviceName The service name
+ */
+ public void addURIMapping(String uri, String serviceName) {
+ String existingMapping = serviceMap.put(uri, serviceName);
+ if (existingMapping != null) {
+ LOG.info("Existing service [" + existingMapping + "] replaced by " +
+ "[" + serviceName + "] for URI [" + uri + "]");
+ } else {
+ LOG.info("Mapped [" + uri + "] to service [" + serviceName + "]");
+ }
+ }
+
+ /**
+ * Sets all uri - service name mappings from a given map.
+ * Any existing mappings are removed
+ *
+ * @param map The map to set from
+ * @throws ClassCastException If any element (key or value) in the map
+ * is not a <code>java.lang.String</code>
+ */
+ public void setMappings(Map map) {
+ serviceMap.clear();
+ for (Iterator iter=map.entrySet().iterator(); iter.hasNext(); ) {
+ Map.Entry entry = (Map.Entry) iter.next();
+ String key = (String) entry.getKey();
+ String value = (String) entry.getValue();
+ addURIMapping(key, value);
+ }
+ }
+
+ /**
+ * Attempts to resolve a service name for the specified request by
+ * looking for an existing matching with the same URI as the specified
+ * request.
+ *
+ * @param request The request for which a service name is to be resolved
+ * @return The name of the service, or <code>null</code> if no
+ * mapping exists for the requests URI
+ */
+ public String resolveService(HttpRequest request) {
+ if (request.getRequestUri().isAbsolute()) {
+ return null;
+ }
+
+ String path = request.getRequestUri().getPath();
+ String serviceName = serviceMap.get(path);
+ if (LOG.isDebugEnabled()) {
+ if (serviceName == null) {
+ LOG.debug("No mapping for path [" + path + "]");
+ } else {
+ LOG.debug("Mapped [" + path + "] to service [" + serviceName + "]");
+ }
+ }
+ return serviceName;
+ }
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/ExactMatchURIServiceResolver.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/ExactMatchURIServiceResolver.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/FixedServiceResolver.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/FixedServiceResolver.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/FixedServiceResolver.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/FixedServiceResolver.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.resolver;
+
+import org.safehaus.asyncweb.common.HttpRequest;
+
+/**
+ * @author Dan Diephouse
+ */
+public class FixedServiceResolver implements ServiceResolver {
+ private String service;
+
+ public String resolveService(HttpRequest request) {
+ return service;
+ }
+
+ public String getService() {
+ return service;
+ }
+
+ public void setService(String service) {
+ this.service = service;
+ }
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/FixedServiceResolver.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/FixedServiceResolver.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/PassThruResolver.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/PassThruResolver.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/PassThruResolver.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/PassThruResolver.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.resolver;
+
+import org.safehaus.asyncweb.common.HttpRequest;
+
+/**
+ * A simple <code>ServiceResolver</code> which passes the full
+ * request URI as the service name, optionally removing any leading
+ * "/"
+ *
+ * @author irvingd
+ *
+ */
+public class PassThruResolver implements ServiceResolver {
+
+ private boolean removeLeadingSlash = true;
+
+ public String resolveService(HttpRequest request) {
+ if (request.getRequestUri().isAbsolute()) {
+ return null;
+ }
+
+ String path = request.getRequestUri().getPath();
+ int length = path.length();
+ if (removeLeadingSlash && length > 0 && path.charAt(0) == '/') {
+ path = length > 1 ? path.substring(1) : "";
+ }
+ return path;
+ }
+
+ public void setRemoveLeadingSlash(boolean removeLeadingSlash) {
+ this.removeLeadingSlash = removeLeadingSlash;
+ }
+
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/PassThruResolver.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/PassThruResolver.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/ServiceResolver.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/ServiceResolver.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/ServiceResolver.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/ServiceResolver.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.resolver;
+
+import org.safehaus.asyncweb.common.HttpRequest;
+
+/**
+ * Resolves the name of the <code>HttpService</code> to be used to
+ * service a request.
+ *
+ * @author irvingd
+ *
+ */
+public interface ServiceResolver {
+
+ /**
+ * Determines the name of the <code>HttpService</code> to be employed
+ * to service a given <code>HttpRequest</code>.<br/>
+ *
+ * If no service can be resolved for the specified request, this method
+ * should return <code>null</code>.
+ *
+ * @param request The request for which a service name is required
+ * @return The name of the <code>HttpService</code> which
+ * should be used to service the request, or
+ * <code>null</code> if no appropriate service can be
+ * found
+ */
+ public String resolveService(HttpRequest request);
+
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/ServiceResolver.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/ServiceResolver.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/SimplePrefixResolver.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/SimplePrefixResolver.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/SimplePrefixResolver.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/SimplePrefixResolver.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.resolver;
+
+import org.safehaus.asyncweb.common.HttpRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A very simple resolver which simply uses the full URI after
+ * stripping an optional prefix as the name of the service.
+ *
+ * <code>SimplePrefixResolver</code> is useful when a very
+ * naming scheme is used - and allows services to be resolved
+ * "dynamically" without any global configuration.<br/>
+ * </br>
+ * Request URIs which do not begin with the configured prefix are
+ * not resolved.<br/>
+ * <br/>
+ * For example, suppose all <code>HttpService</code>s are addressed
+ * under the prefix <code>/services/</code>. We would then map as
+ * follows for the following URIs:<br/>
+ * <br/>
+ * <table border="1" cellpadding="2">
+ * <tr><td>URI</td><td>Service Name</td></tr>
+ * <tr><td>/services/serviceA</td><td>serviceA</td></tr>
+ * <tr><td>/services/serviceB</td><td>serviceB</td></tr>
+ * <tr><td>/services/x/serviceX</td><td>x/serviceA</td></tr>
+ * <tr><td>/x/serviceA</td><td>null</td></tr>
+ * </table>
+ *
+ * @author irvingd
+ *
+ */
+public class SimplePrefixResolver implements ServiceResolver {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SimplePrefixResolver.class);
+
+ // FIXME Rename to pathPrefix.
+ private String uriPrefix;
+
+ /**
+ * Sets the prefix associated with this resolver.
+ * URIs which begin with the specified prefix are resolved to the URI
+ * with the prefix stripped. URIs which do not begin with the specified
+ * prefix are not resolved.<br/>
+ * <br/>
+ * If a prefix is not set, requests are resolved to their URI value.
+ *
+ * @param uriPrefix The uri prefix to apply
+ */
+ public void setUriPrefix(String uriPrefix) {
+ this.uriPrefix = uriPrefix;
+ LOG.info("URI prefix: " + uriPrefix);
+ }
+
+ /**
+ * Resolves the name of the service to be employed for the specified request.
+ * If this resolver is not configured with a prefix, the request resoves to
+ * the request URI.<br/>
+ * Otherwise, if the request URI begins with the configured prefix, the request
+ * resolves to the URI with the prefix stripped. If the request URI does not
+ * begin with the configured prefix, the request is unresolved
+ *
+ * @param request The request to resolve to a service name
+ * @return The resolved service name, or <code>null</code> if
+ * the request is un-resolved
+ */
+ public String resolveService(HttpRequest request) {
+ if (request.getRequestUri() == null || request.getRequestUri().isAbsolute()) {
+ return null;
+ }
+
+ String path = request.getRequestUri().getPath();
+ if (uriPrefix != null && path != null) {
+ if (path.startsWith(uriPrefix)) {
+ path = path.substring(uriPrefix.length());
+ } else {
+ path = null;
+ }
+ }
+ if (LOG.isInfoEnabled()) {
+ LOG.info("Resolved request to service name: " + path);
+ }
+ return path;
+ }
+
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/SimplePrefixResolver.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/resolver/SimplePrefixResolver.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/session/BasicSession.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/session/BasicSession.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/session/BasicSession.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/session/BasicSession.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.session;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.safehaus.asyncweb.service.HttpSession;
+import org.safehaus.asyncweb.util.TimedPermit;
+
+/**
+ * A basic <code>Session</code> implementation which holds session values
+ * in memory
+ *
+ * @author irvingd
+ *
+ */
+class BasicSession implements HttpSession {
+
+ private TimedPermit permit;
+ private boolean isAttached;
+ private boolean isDestroyed;
+ private Object lock = new Object();
+ private BasicSessionStore owner;
+ private String id;
+
+ private Map<String, Object> values = Collections.synchronizedMap(new HashMap<String, Object>());
+
+ /**
+ * @param owner The owner of this session
+ */
+ BasicSession(String id, BasicSessionStore owner) {
+ this.owner = owner;
+ this.id = id;
+ }
+
+ public Object getValue(String key) {
+ return values.get(key);
+ }
+
+ public void setValue(String key, Object value) {
+ values.put(key, value);
+ }
+
+ public Object removeValue(String key) {
+ return values.remove(key);
+ }
+
+ public boolean isAttached() {
+ return isAttached;
+ }
+
+ public boolean isValid() {
+ synchronized (lock) {
+ return !isDestroyed;
+ }
+ }
+
+ /**
+ * Destroys this session if it is not already destroyed.
+ * If destruction takes place, notifications are fired.
+ */
+ public void destroy() {
+ if (destroyIfActive()) {
+ owner.sessionDestroyed(this);
+ }
+ }
+
+ /**
+ * @return The id of this session
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Instructs this session to expire.
+ * If this session is not already expired, expiration notifications
+ * are fired
+ */
+ void expire() {
+ if (destroyIfActive()) {
+ owner.sessionExpired(this);
+ }
+ }
+
+ /**
+ * Sets the permit associated with this session
+ *
+ * @param permit This sessions access permit
+ */
+ void setPermit(TimedPermit permit) {
+ this.permit = permit;
+ }
+
+ /**
+ * Invoked when this session is referenced by a client request.
+ * The permit associated with this session is renewed, and subsequent calls
+ * to <code>isAttached</code> will return <code>true</code>
+ */
+ void access() {
+ permit.renew();
+ isAttached = true;
+ }
+
+ /**
+ * Destroys this session if it is not destroyed already.
+ *
+ * @return <code>true</code> if this session is successfully
+ */
+ private boolean destroyIfActive() {
+ synchronized (lock) {
+ if (isDestroyed) {
+ return false;
+ }
+ isDestroyed = true;
+ }
+ permit.cancel();
+ return true;
+ }
+
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/session/BasicSession.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/session/BasicSession.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/session/BasicSessionStore.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/session/BasicSessionStore.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/session/BasicSessionStore.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/session/BasicSessionStore.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,277 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.session;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.safehaus.asyncweb.service.HttpSession;
+import org.safehaus.asyncweb.util.LinkedPermitIssuer;
+import org.safehaus.asyncweb.util.PermitExpirationListener;
+import org.safehaus.asyncweb.util.TimedPermit;
+import org.safehaus.asyncweb.util.TimedPermitIssuer;
+
+/**
+ * A simple <code>SessionStore</code> implementation which holds all session
+ * data in memory. A <code>TimedPermitIssuer</code> is employed to issue a time-out
+ * permit for each issued session.
+ *
+ * @author irvingd
+ *
+ */
+public class BasicSessionStore implements HttpSessionStore {
+
+ private static final Logger LOG = LoggerFactory.getLogger(BasicSessionStore.class);
+
+ /**
+ * Default session timeout of 15 minutes
+ */
+ private static final long DEFAULT_SESSION_TIMEOUT = 900000;
+
+ private Map<String, HttpSession> sessionMap = Collections.synchronizedMap(new HashMap<String, HttpSession>());
+ private List<HttpSessionListener> listeners = Collections.synchronizedList(new ArrayList<HttpSessionListener>());
+
+ private TimedPermitIssuer permitIssuer;
+ private boolean isClosed;
+
+ /**
+ * Constructs with the default session timeout
+ */
+ public BasicSessionStore() {
+ this(DEFAULT_SESSION_TIMEOUT);
+ }
+
+ /**
+ * Constructs with a specified session timeout
+ *
+ * @param sessionTimeout The session timeout (in ms)
+ */
+ public BasicSessionStore(long sessionTimeout) {
+ permitIssuer = new LinkedPermitIssuer(sessionTimeout);
+ permitIssuer.addPermitExpirationListener(new TimeoutListener());
+ LOG.info("BasicSessionStore timeout: " + sessionTimeout + "ms");
+ }
+
+ /**
+ * Adds a listener to this store
+ *
+ * @param listener The listener to add
+ */
+ public void addSessionListener(HttpSessionListener listener) {
+ listeners.add(listener);
+ }
+
+ /**
+ * Sets the listeners employed by this store.
+ * Any existing listeners are removed
+ *
+ * @param listeners The listeners to be added
+ */
+ public void setSessionListeners(Collection<HttpSessionListener> listeners) {
+ synchronized (this.listeners) {
+ this.listeners.clear();
+ this.listeners.addAll(listeners);
+ }
+ }
+
+ /**
+ * Closes this store.
+ * Our permit issuer is closed, and all sessions are destroyed.
+ */
+ public void close() {
+ List<HttpSession> closureList = null;
+
+ synchronized (sessionMap) {
+ if (isClosed) {
+ LOG.debug("Already closed");
+ return;
+ }
+ LOG.debug("BasicSessionStore closing");
+ permitIssuer.close();
+ isClosed = true;
+ closureList = new ArrayList<HttpSession>(sessionMap.values());
+ }
+ for (Iterator<HttpSession> iter = closureList.iterator(); iter.hasNext(); ) {
+ BasicSession session = (BasicSession) iter.next();
+ LOG.debug("Closure: Destroying session: " + session.getId());
+ session.destroy();
+ }
+ }
+
+ /**
+ * Creates a new session for the specified key.
+ *
+ * @param key The session key
+ * @return The created session, or <code>null</code> if a session is already
+ * held for the specified key
+ */
+ public HttpSession createSession(String key) {
+ BasicSession created = null;
+ synchronized (sessionMap) {
+ if (isClosed) {
+ throw new IllegalStateException("Store closed");
+ }
+ if (!sessionMap.containsKey(key)) {
+ created = new BasicSession(key, this);
+ sessionMap.put(key, created);
+ TimedPermit permit = permitIssuer.issuePermit(created);
+ created.setPermit(permit);
+ }
+ }
+ if (created != null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("New session created with key '" + key + "'. Firing notifications");
+ }
+ fireCreated(created);
+ }
+ return created;
+ }
+
+ /**
+ * Locates the session with the specified key.
+ * If the session is found, we request it to renew its access permit.
+ *
+ * @param key The key for which a session is required
+ * @return The located session, or <code>null</code> if no session with the
+ * specified key was found
+ */
+ public HttpSession locateSession(String key) {
+ BasicSession session = (BasicSession) sessionMap.get(key);
+ if (session != null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Located session with key '" + key + "'. Marking as accessed");
+ }
+ session.access();
+ }
+ return session;
+ }
+
+ /**
+ * Invoked by a session we created when it successfully processes an expiry.
+ * The session is removed from our session map, and expiry notifications are fired.
+ *
+ * @param session The expired session
+ */
+ void sessionExpired(BasicSession session) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Session has been expired. Processing notifications for '" + session.getId() + "'");
+ }
+ sessionMap.remove(session.getId());
+ fireExpiry(session);
+ }
+
+ /**
+ * Invoked by a session we created when it successfully processes a destruction
+ * request.
+ * The session is removed from our session map, and destruction notifications
+ * are fired
+ *
+ * @param session The destroyed session
+ */
+ void sessionDestroyed(BasicSession session) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Session has been destroyed. Processing notifications for '" + session.getId() + "'");
+ }
+ sessionMap.remove(session.getId());
+ fireDestroyed(session);
+ }
+
+ /**
+ * Invoked when the permit associated with the specified session expires.
+ * We simply request the session to expire itself.
+ * If the session is not already destroyed, it will request us to fire
+ * notifications on its behalf.
+ *
+ * @param session The expired session
+ */
+ private void sessionPermitExpired(BasicSession session) {
+ session.expire();
+ }
+
+ /**
+ * Fires creation notification to all listeners assocaited with this store
+ *
+ * @param session The expired session
+ */
+ private void fireCreated(HttpSession session) {
+ synchronized (listeners) {
+ for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
+ HttpSessionListener listener = (HttpSessionListener) iter.next();
+ listener.sessionCreated(session);
+ }
+ }
+ }
+
+ /**
+ * Fires destruction notification to all listeners assocaited with this store
+ *
+ * @param session The expired session
+ */
+ private void fireDestroyed(HttpSession session) {
+ synchronized (listeners) {
+ for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
+ HttpSessionListener listener = (HttpSessionListener) iter.next();
+ listener.sessionDestroyed(session);
+ }
+ }
+ }
+
+ /**
+ * Fires expiry notification to all listeners assocaited with this store
+ *
+ * @param session The expired session
+ */
+ private void fireExpiry(HttpSession session) {
+ synchronized (listeners) {
+ for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
+ HttpSessionListener listener = (HttpSessionListener) iter.next();
+ listener.sessionExpired(session);
+ }
+ }
+ }
+
+ /**
+ * Receives notifications of timed out permits issued by this store,
+ * and triggers expiry of the associated session
+ *
+ * @author irvingd
+ *
+ */
+ private class TimeoutListener implements PermitExpirationListener {
+
+ /**
+ * Invoked when a permit issued for a session expires
+ *
+ * @param session The session which has expired
+ */
+ public void permitExpired(Object session) {
+ sessionPermitExpired((BasicSession)session);
+ }
+
+ }
+
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/session/BasicSessionStore.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/session/BasicSessionStore.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/session/CookieIdentifier.java
URL: http://svn.apache.org/viewvc/mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/session/CookieIdentifier.java?rev=587364&view=auto
==============================================================================
--- mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/session/CookieIdentifier.java (added)
+++ mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/session/CookieIdentifier.java Mon Oct 22 19:29:38 2007
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.safehaus.asyncweb.service.session;
+
+import org.safehaus.asyncweb.common.Cookie;
+import org.safehaus.asyncweb.common.DefaultCookie;
+import org.safehaus.asyncweb.common.HttpRequest;
+import org.safehaus.asyncweb.common.MutableCookie;
+import org.safehaus.asyncweb.common.MutableHttpResponse;
+
+
+/**
+ * A <code>SessionIdentifier</code> which adds and extracts session key
+ * cookies
+ *
+ * @author irvingd
+ *
+ */
+public class CookieIdentifier implements HttpSessionIdentifier {
+
+ /**
+ * The name of the cookie
+ */
+ private static final String SESSION_ID_COOKIE = "sessionKey";
+
+ private String cookieId = SESSION_ID_COOKIE;
+
+ /**
+ * Sets the name of the cookie used for holding session keys.
+ * The default cookie name is <code>sessionKey</code>
+ *
+ * @param cookieId The cookie name to be used
+ */
+ public void setCookieId(String cookieId) {
+ this.cookieId = cookieId;
+ }
+
+ /**
+ * Extracts a session key from the session cookie supplied with the request -
+ * if any
+ *
+ * @param request The request
+ * @return The session key, or null if a session cookie was not located
+ */
+ public String getSessionKey(HttpRequest request) {
+ Cookie sessionCookie = null;
+ for (Cookie c: request.getCookies()) {
+ if (c.getName().equals(cookieId)) {
+ sessionCookie = c;
+ break;
+ }
+ }
+ return sessionCookie == null ? null : sessionCookie.getValue();
+ }
+
+ /**
+ * Adds a session cookie to the specified request
+ *
+ * @param key The session key
+ * @param response The response
+ */
+ public void addSessionKey(String key, MutableHttpResponse response) {
+ MutableCookie sessionCookie = new DefaultCookie(cookieId);
+ sessionCookie.setMaxAge(-1); // "non-persistent"
+ sessionCookie.setValue(key);
+ // TODO: Set "isSecure" based on whether the request came in over
+ // a secure transport
+ response.addCookie(sessionCookie);
+ }
+}
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/session/CookieIdentifier.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: mina/sandbox/asyncweb/core/src/main/java/org/safehaus/asyncweb/service/session/CookieIdentifier.java
------------------------------------------------------------------------------
svn:keywords = Rev Date