blob: 6a7b4063c61f7d55b92605b7b6c86c61cdc67f14 [file] [log] [blame]
/*
* 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.apache.asyncweb.server.context;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import org.apache.asyncweb.common.*;
import org.apache.asyncweb.common.HttpResponse;
import org.apache.asyncweb.common.HttpResponseStatus;
import org.apache.asyncweb.common.MutableHttpResponse;
import org.apache.asyncweb.server.HttpServiceContext;
import org.apache.asyncweb.server.HttpSession;
import org.apache.asyncweb.server.ServiceContainer;
import org.apache.asyncweb.server.HttpClientListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A default implementation of {@link HttpServiceContext}.
*
* @author The Apache MINA Project (dev@mina.apache.org)
*/
public abstract class AbstractHttpServiceContext implements HttpServiceContext
{
private final Logger log = LoggerFactory.getLogger( AbstractHttpServiceContext.class );
private final InetSocketAddress remoteAddress;
private final InetSocketAddress localAddress;
private final HttpRequest request;
private HttpResponse committedResponse;
private HttpSession session;
private boolean createdSession;
private final ServiceContainer container;
private final ArrayList<HttpClientListener> listeners = new ArrayList<HttpClientListener>( 2 );
public AbstractHttpServiceContext( InetSocketAddress localAddress, InetSocketAddress remoteAddress,
HttpRequest request, ServiceContainer container )
{
if ( remoteAddress == null )
{
throw new NullPointerException( "remoteAddress" );
}
if ( localAddress == null )
{
throw new NullPointerException( "localAddress" );
}
if ( request == null )
{
throw new NullPointerException( "request" );
}
if ( container == null )
{
throw new NullPointerException( "container" );
}
this.remoteAddress = remoteAddress;
this.localAddress = localAddress;
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() )
{
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 InetSocketAddress getLocalAddress()
{
return localAddress;
}
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 void fireClientDisconnected()
{
ArrayList<HttpClientListener> cloned;
synchronized( listeners )
{
//noinspection unchecked
cloned = ( ArrayList<HttpClientListener> ) listeners.clone();
}
for ( HttpClientListener listener : cloned )
{
listener.clientDisconnected( this );
}
}
protected void fireClientIdle( long idleTime, int idleCount )
{
ArrayList<HttpClientListener> cloned;
synchronized( listeners )
{
//noinspection unchecked
cloned = ( ArrayList<HttpClientListener> ) listeners.clone();
}
for ( HttpClientListener listener : cloned )
{
listener.clientIdle( this, idleTime, idleCount );
}
}
public boolean addClientListener( HttpClientListener listener )
{
return listeners.add( listener );
}
public boolean removeClientListener( HttpClientListener listener )
{
return listeners != null && listeners.remove( listener );
}
protected abstract void doWrite( boolean requiresClosure );
}