001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *
019: */
020: package org.safehaus.asyncweb.service;
021:
022: import java.util.HashMap;
023: import java.util.Iterator;
024: import java.util.Map;
025:
026: import org.safehaus.asyncweb.common.DefaultHttpResponse;
027: import org.safehaus.asyncweb.common.HttpRequest;
028: import org.safehaus.asyncweb.common.HttpResponseStatus;
029: import org.safehaus.asyncweb.common.MutableHttpResponse;
030: import org.safehaus.asyncweb.service.resolver.ServiceResolver;
031: import org.slf4j.Logger;
032: import org.slf4j.LoggerFactory;
033:
034: /**
035: * A <code>ServiceHandler</code> which employs a <code>ServiceResolver</code>
036: * to map incoming requests to an <code>HttpService</code> which is
037: * then invoked.
038: * If an incoming request can not be mapped to an <code>HttpService</code>,
039: * a <code>404</code> response status is returned to the client
040: *
041: * @author irvingd
042: *
043: */
044: public class HttpServiceHandler implements HttpServiceFilter {
045:
046: private static final Logger LOG = LoggerFactory
047: .getLogger(HttpServiceHandler.class);
048:
049: private ServiceResolver resolver;
050: private Map<String, HttpService> serviceMap = new HashMap<String, HttpService>();
051:
052: /**
053: * Adds an <code>HttpService</code> against a service name.
054: * The service will be invoked this handlers associated
055: * <code>ServiceResolver</code> resolves a request to the
056: * specified service name.<br/>
057: *
058: * Any existing registration against the given name is overwritten.
059: *
060: * @param name The service name
061: * @param httpService The service
062: */
063: public void addHttpService(String name, HttpService httpService) {
064: Object oldService = serviceMap.put(name, httpService);
065: if (oldService != null && LOG.isWarnEnabled()) {
066: LOG.warn("Duplicate mapping for '" + name
067: + "'. Previous mapping removed");
068: }
069: LOG.info("New HttpService registered against key '" + name
070: + "'");
071: }
072:
073: /**
074: * Associates this handler with the <code>ServiceResolver</code>
075: * it is to employ
076: *
077: * @param resolver The resolver to employ
078: */
079: public void setServiceResolver(ServiceResolver resolver) {
080: LOG
081: .info("Associated with service resolver [ " + resolver
082: + "]");
083: this .resolver = resolver;
084: }
085:
086: /**
087: * Attempts to resolve the specified request to an <code>HttpService</code>
088: * known to this handler by employing this handlers associated
089: * <code>ServiceResolver</code>.<br/>
090: * If an <code>HttpService</code> is located for the request, it is provided
091: * with the request. Otherwise, a <code>404</code> response is committed
092: * for the request
093: */
094: public void handleRequest(NextFilter next,
095: HttpServiceContext context) throws Exception {
096: HttpService service = null;
097: HttpRequest request = context.getRequest();
098: String serviceName = resolver.resolveService(request);
099: if (serviceName != null) {
100: service = serviceMap.get(serviceName);
101: }
102: if (service == null) {
103: handleUnmappedRequest(context);
104: } else {
105: if (LOG.isInfoEnabled()) {
106: LOG.info("Mapped request [" + request.getRequestUri()
107: + "] to " + "service '" + serviceName + "'");
108: }
109: service.handleRequest(context);
110: next.invoke();
111: }
112: }
113:
114: /**
115: * Handles a response. This handler does not perform any
116: * action for responses - so the specified {@link NextFilter} is invoked immediately.
117: */
118: public void handleResponse(NextFilter next,
119: HttpServiceContext context) {
120: next.invoke();
121: }
122:
123: /**
124: * Starts this handler.
125: */
126: public void start() {
127: LOG.info("HttpServiceHandler starting");
128: for (Iterator iter = serviceMap.entrySet().iterator(); iter
129: .hasNext();) {
130: Map.Entry entry = (Map.Entry) iter.next();
131: String serviceName = (String) entry.getKey();
132: HttpService service = (HttpService) entry.getValue();
133: LOG.info("Starting HttpService '" + serviceName + "'");
134: service.start();
135: LOG.info("HttpService '" + serviceName + "' started");
136: }
137: }
138:
139: /**
140: * Stops this handler
141: */
142: public void stop() {
143: LOG.info("HttpServiceHandler stopping");
144: for (Iterator iter = serviceMap.entrySet().iterator(); iter
145: .hasNext();) {
146: Map.Entry entry = (Map.Entry) iter.next();
147: String serviceName = (String) entry.getKey();
148: HttpService service = (HttpService) entry.getValue();
149: LOG.info("Stopping HttpService '" + serviceName + "'");
150: service.stop();
151: LOG.info("HttpService '" + serviceName + "' stopped");
152: }
153: }
154:
155: /**
156: * Handles an unmapped request by issuing a <code>404</code>
157: * response to the client
158: */
159: private void handleUnmappedRequest(HttpServiceContext context) {
160: HttpRequest request = context.getRequest();
161: if (LOG.isWarnEnabled()) {
162: LOG.warn("Failed to map '" + request.getRequestUri()
163: + "' to " + "a resource");
164: }
165: MutableHttpResponse response = new DefaultHttpResponse();
166: response.setStatus(HttpResponseStatus.NOT_FOUND);
167: response.setStatusReasonPhrase(request.getRequestUri()
168: .toString());
169: context.commitResponse(response);
170: }
171: }
|