001/*
002 * ====================================================================
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 * ====================================================================
020 *
021 * This software consists of voluntary contributions made by many
022 * individuals on behalf of the Apache Software Foundation.  For more
023 * information on the Apache Software Foundation, please see
024 * <http://www.apache.org/>.
025 *
026 */
027
028package org.apache.http.impl.nio.reactor;
029
030import java.io.IOException;
031
032import org.apache.http.nio.reactor.IOEventDispatch;
033import org.apache.http.nio.reactor.IOSession;
034import org.apache.http.nio.reactor.ssl.SSLIOSession;
035import org.apache.http.util.Asserts;
036
037/**
038 * Abstract {@link IOEventDispatch} implementation that supports both plain (non-encrypted)
039 * and SSL encrypted HTTP connections.
040 *
041 * @param <T> the connection type.
042 * @since 4.2
043 */
044public abstract class AbstractIODispatch<T> implements IOEventDispatch {
045
046    protected abstract T createConnection(IOSession session);
047
048    protected abstract void onConnected(T conn);
049
050    protected abstract void onClosed(T conn);
051
052    protected abstract void onException(T conn, IOException ex);
053
054    protected abstract void onInputReady(T conn);
055
056    protected abstract void onOutputReady(T conn);
057
058    protected abstract void onTimeout(T conn);
059
060    private void ensureNotNull(final T conn) {
061        Asserts.notNull(conn, "HTTP connection");
062    }
063
064    @Override
065    public void connected(final IOSession session) {
066        @SuppressWarnings("unchecked")
067        T conn = (T) session.getAttribute(IOEventDispatch.CONNECTION_KEY);
068        try {
069            if (conn == null) {
070                conn = createConnection(session);
071                session.setAttribute(IOEventDispatch.CONNECTION_KEY, conn);
072            }
073            onConnected(conn);
074            final SSLIOSession ssliosession = (SSLIOSession) session.getAttribute(
075                    SSLIOSession.SESSION_KEY);
076            if (ssliosession != null) {
077                try {
078                    synchronized (ssliosession) {
079                        if (!ssliosession.isInitialized()) {
080                            ssliosession.initialize();
081                        }
082                    }
083                } catch (final IOException ex) {
084                    onException(conn, ex);
085                    ssliosession.shutdown();
086                }
087            }
088        } catch (final RuntimeException ex) {
089            session.shutdown();
090            throw ex;
091        }
092    }
093
094    @Override
095    public void disconnected(final IOSession session) {
096        @SuppressWarnings("unchecked")
097        final
098        T conn = (T) session.getAttribute(IOEventDispatch.CONNECTION_KEY);
099        if (conn != null) {
100            onClosed(conn);
101        }
102    }
103
104    @Override
105    public void inputReady(final IOSession session) {
106        @SuppressWarnings("unchecked")
107        final
108        T conn = (T) session.getAttribute(IOEventDispatch.CONNECTION_KEY);
109        try {
110            ensureNotNull(conn);
111            final SSLIOSession ssliosession = (SSLIOSession) session.getAttribute(
112                    SSLIOSession.SESSION_KEY);
113            if (ssliosession == null) {
114                onInputReady(conn);
115            } else {
116                try {
117                    if (!ssliosession.isInitialized()) {
118                        ssliosession.initialize();
119                    }
120                    if (ssliosession.isAppInputReady()) {
121                        onInputReady(conn);
122                    }
123                    ssliosession.inboundTransport();
124                } catch (final IOException ex) {
125                    onException(conn, ex);
126                    ssliosession.shutdown();
127                }
128            }
129        } catch (final RuntimeException ex) {
130            session.shutdown();
131            throw ex;
132        }
133    }
134
135    @Override
136    public void outputReady(final IOSession session) {
137        @SuppressWarnings("unchecked")
138        final
139        T conn = (T) session.getAttribute(IOEventDispatch.CONNECTION_KEY);
140        try {
141            ensureNotNull(conn);
142            final SSLIOSession ssliosession = (SSLIOSession) session.getAttribute(
143                    SSLIOSession.SESSION_KEY);
144            if (ssliosession == null) {
145                onOutputReady(conn);
146            } else {
147                try {
148                    if (!ssliosession.isInitialized()) {
149                        ssliosession.initialize();
150                    }
151                    if (ssliosession.isAppOutputReady()) {
152                        onOutputReady(conn);
153                    }
154                    ssliosession.outboundTransport();
155                } catch (final IOException ex) {
156                    onException(conn, ex);
157                    ssliosession.shutdown();
158                }
159            }
160        } catch (final RuntimeException ex) {
161            session.shutdown();
162            throw ex;
163        }
164    }
165
166    @Override
167    public void timeout(final IOSession session) {
168        @SuppressWarnings("unchecked")
169        final
170        T conn = (T) session.getAttribute(IOEventDispatch.CONNECTION_KEY);
171        try {
172            final SSLIOSession ssliosession = (SSLIOSession) session.getAttribute(
173                    SSLIOSession.SESSION_KEY);
174            ensureNotNull(conn);
175            onTimeout(conn);
176            if (ssliosession != null) {
177                synchronized (ssliosession) {
178                    if (ssliosession.isOutboundDone() && !ssliosession.isInboundDone()) {
179                        // The session failed to terminate cleanly
180                        ssliosession.shutdown();
181                    }
182                }
183            }
184        } catch (final RuntimeException ex) {
185            session.shutdown();
186            throw ex;
187        }
188    }
189
190}