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; 031import java.net.SocketAddress; 032import java.nio.channels.Channel; 033import java.nio.channels.SelectionKey; 034 035import org.apache.http.annotation.ThreadingBehavior; 036import org.apache.http.annotation.Contract; 037import org.apache.http.nio.reactor.IOSession; 038import org.apache.http.nio.reactor.SessionRequest; 039import org.apache.http.nio.reactor.SessionRequestCallback; 040import org.apache.http.util.Args; 041 042/** 043 * Default implementation of {@link SessionRequest}. 044 * 045 * @since 4.0 046 */ 047@Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL) 048public class SessionRequestImpl implements SessionRequest { 049 050 private volatile boolean completed; 051 private volatile SelectionKey key; 052 053 private final SocketAddress remoteAddress; 054 private final SocketAddress localAddress; 055 private final Object attachment; 056 private final SessionRequestCallback callback; 057 058 private volatile int connectTimeout; 059 private volatile IOSession session = null; 060 private volatile IOException exception = null; 061 062 public SessionRequestImpl( 063 final SocketAddress remoteAddress, 064 final SocketAddress localAddress, 065 final Object attachment, 066 final SessionRequestCallback callback) { 067 super(); 068 Args.notNull(remoteAddress, "Remote address"); 069 this.remoteAddress = remoteAddress; 070 this.localAddress = localAddress; 071 this.attachment = attachment; 072 this.callback = callback; 073 this.connectTimeout = 0; 074 } 075 076 @Override 077 public SocketAddress getRemoteAddress() { 078 return this.remoteAddress; 079 } 080 081 @Override 082 public SocketAddress getLocalAddress() { 083 return this.localAddress; 084 } 085 086 @Override 087 public Object getAttachment() { 088 return this.attachment; 089 } 090 091 @Override 092 public boolean isCompleted() { 093 return this.completed; 094 } 095 096 protected void setKey(final SelectionKey key) { 097 this.key = key; 098 } 099 100 @Override 101 public void waitFor() throws InterruptedException { 102 if (this.completed) { 103 return; 104 } 105 synchronized (this) { 106 while (!this.completed) { 107 wait(); 108 } 109 } 110 } 111 112 @Override 113 public IOSession getSession() { 114 synchronized (this) { 115 return this.session; 116 } 117 } 118 119 @Override 120 public IOException getException() { 121 synchronized (this) { 122 return this.exception; 123 } 124 } 125 126 public void completed(final IOSession session) { 127 Args.notNull(session, "Session"); 128 if (this.completed) { 129 return; 130 } 131 this.completed = true; 132 synchronized (this) { 133 this.session = session; 134 if (this.callback != null) { 135 this.callback.completed(this); 136 } 137 notifyAll(); 138 } 139 } 140 141 public void failed(final IOException exception) { 142 if (exception == null) { 143 return; 144 } 145 if (this.completed) { 146 return; 147 } 148 this.completed = true; 149 final SelectionKey key = this.key; 150 if (key != null) { 151 key.cancel(); 152 final Channel channel = key.channel(); 153 try { 154 channel.close(); 155 } catch (final IOException ignore) {} 156 } 157 synchronized (this) { 158 this.exception = exception; 159 if (this.callback != null) { 160 this.callback.failed(this); 161 } 162 notifyAll(); 163 } 164 } 165 166 public void timeout() { 167 if (this.completed) { 168 return; 169 } 170 this.completed = true; 171 final SelectionKey key = this.key; 172 if (key != null) { 173 key.cancel(); 174 final Channel channel = key.channel(); 175 if (channel.isOpen()) { 176 try { 177 channel.close(); 178 } catch (final IOException ignore) {} 179 } 180 } 181 synchronized (this) { 182 if (this.callback != null) { 183 this.callback.timeout(this); 184 } 185 } 186 } 187 188 @Override 189 public int getConnectTimeout() { 190 return this.connectTimeout; 191 } 192 193 @Override 194 public void setConnectTimeout(final int timeout) { 195 if (this.connectTimeout != timeout) { 196 this.connectTimeout = timeout; 197 final SelectionKey key = this.key; 198 if (key != null) { 199 key.selector().wakeup(); 200 } 201 } 202 } 203 204 @Override 205 public void cancel() { 206 if (this.completed) { 207 return; 208 } 209 this.completed = true; 210 final SelectionKey key = this.key; 211 if (key != null) { 212 key.cancel(); 213 final Channel channel = key.channel(); 214 if (channel.isOpen()) { 215 try { 216 channel.close(); 217 } catch (final IOException ignore) {} 218 } 219 } 220 synchronized (this) { 221 if (this.callback != null) { 222 this.callback.cancelled(this); 223 } 224 notifyAll(); 225 } 226 } 227 228}