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.ListenerEndpoint; 038import org.apache.http.util.Args; 039 040/** 041 * Default implementation of {@link ListenerEndpoint}. 042 * 043 * @since 4.0 044 */ 045@Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL) 046public class ListenerEndpointImpl implements ListenerEndpoint { 047 048 private volatile boolean completed; 049 private volatile boolean closed; 050 private volatile SelectionKey key; 051 private volatile SocketAddress address; 052 private volatile IOException exception; 053 054 private final ListenerEndpointClosedCallback callback; 055 056 public ListenerEndpointImpl( 057 final SocketAddress address, 058 final ListenerEndpointClosedCallback callback) { 059 super(); 060 Args.notNull(address, "Address"); 061 this.address = address; 062 this.callback = callback; 063 } 064 065 @Override 066 public SocketAddress getAddress() { 067 return this.address; 068 } 069 070 public boolean isCompleted() { 071 return this.completed; 072 } 073 074 @Override 075 public IOException getException() { 076 return this.exception; 077 } 078 079 @Override 080 public void waitFor() throws InterruptedException { 081 if (this.completed) { 082 return; 083 } 084 synchronized (this) { 085 while (!this.completed) { 086 wait(); 087 } 088 } 089 } 090 091 public void completed(final SocketAddress address) { 092 Args.notNull(address, "Address"); 093 if (this.completed) { 094 return; 095 } 096 this.completed = true; 097 synchronized (this) { 098 this.address = address; 099 notifyAll(); 100 } 101 } 102 103 public void failed(final IOException exception) { 104 if (exception == null) { 105 return; 106 } 107 if (this.completed) { 108 return; 109 } 110 this.completed = true; 111 synchronized (this) { 112 this.exception = exception; 113 notifyAll(); 114 } 115 } 116 117 public void cancel() { 118 if (this.completed) { 119 return; 120 } 121 this.completed = true; 122 this.closed = true; 123 synchronized (this) { 124 notifyAll(); 125 } 126 } 127 128 protected void setKey(final SelectionKey key) { 129 this.key = key; 130 } 131 132 @Override 133 public boolean isClosed() { 134 return this.closed || (this.key != null && !this.key.isValid()); 135 } 136 137 @Override 138 public void close() { 139 if (this.closed) { 140 return; 141 } 142 this.completed = true; 143 this.closed = true; 144 if (this.key != null) { 145 this.key.cancel(); 146 final Channel channel = this.key.channel(); 147 try { 148 channel.close(); 149 } catch (final IOException ignore) {} 150 } 151 if (this.callback != null) { 152 this.callback.endpointClosed(this); 153 } 154 synchronized (this) { 155 notifyAll(); 156 } 157 } 158 159 @Override 160 public String toString() { 161 return "[address=" + address + ", key=" + key + ", closed=" + closed + ", completed=" 162 + completed + ", exception=" + exception + ", callback=" + callback + "]"; 163 } 164 165}