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 */ 020package org.apache.mina.transport.vmpipe; 021 022import java.io.IOException; 023import java.net.SocketAddress; 024import java.util.HashMap; 025import java.util.HashSet; 026import java.util.List; 027import java.util.Map; 028import java.util.Set; 029import java.util.concurrent.Executor; 030 031import org.apache.mina.core.future.IoFuture; 032import org.apache.mina.core.service.AbstractIoAcceptor; 033import org.apache.mina.core.service.IoHandler; 034import org.apache.mina.core.service.TransportMetadata; 035import org.apache.mina.core.session.IdleStatusChecker; 036import org.apache.mina.core.session.IoSession; 037 038/** 039 * Binds the specified {@link IoHandler} to the specified 040 * {@link VmPipeAddress}. 041 * 042 * @author <a href="http://mina.apache.org">Apache MINA Project</a> 043 */ 044public final class VmPipeAcceptor extends AbstractIoAcceptor { 045 046 // object used for checking session idle 047 private IdleStatusChecker idleChecker; 048 049 static final Map<VmPipeAddress, VmPipe> boundHandlers = new HashMap<VmPipeAddress, VmPipe>(); 050 051 /** 052 * Creates a new instance. 053 */ 054 public VmPipeAcceptor() { 055 this(null); 056 } 057 058 /** 059 * Creates a new instance. 060 * 061 * @param executor The executor to use 062 */ 063 public VmPipeAcceptor(Executor executor) { 064 super(new DefaultVmPipeSessionConfig(), executor); 065 idleChecker = new IdleStatusChecker(); 066 // we schedule the idle status checking task in this service exceutor 067 // it will be woke up every seconds 068 executeWorker(idleChecker.getNotifyingTask(), "idleStatusChecker"); 069 } 070 071 /** 072 * {@inheritDoc} 073 */ 074 public TransportMetadata getTransportMetadata() { 075 return VmPipeSession.METADATA; 076 } 077 078 /** 079 * {@inheritDoc} 080 */ 081 public VmPipeSessionConfig getSessionConfig() { 082 return (VmPipeSessionConfig) sessionConfig; 083 } 084 085 /** 086 * {@inheritDoc} 087 */ 088 @Override 089 public VmPipeAddress getLocalAddress() { 090 return (VmPipeAddress) super.getLocalAddress(); 091 } 092 093 /** 094 * {@inheritDoc} 095 */ 096 @Override 097 public VmPipeAddress getDefaultLocalAddress() { 098 return (VmPipeAddress) super.getDefaultLocalAddress(); 099 } 100 101 // This method is overriden to work around a problem with 102 // bean property access mechanism. 103 /** 104 * Sets the local Address for this acceptor 105 * 106 * @param localAddress The local address to use 107 */ 108 public void setDefaultLocalAddress(VmPipeAddress localAddress) { 109 super.setDefaultLocalAddress(localAddress); 110 } 111 112 /** 113 * {@inheritDoc} 114 */ 115 @Override 116 protected void dispose0() throws Exception { 117 // stop the idle checking task 118 idleChecker.getNotifyingTask().cancel(); 119 unbind(); 120 } 121 122 /** 123 * {@inheritDoc} 124 */ 125 @Override 126 protected Set<SocketAddress> bindInternal(List<? extends SocketAddress> localAddresses) throws IOException { 127 Set<SocketAddress> newLocalAddresses = new HashSet<SocketAddress>(); 128 129 synchronized (boundHandlers) { 130 for (SocketAddress a : localAddresses) { 131 VmPipeAddress localAddress = (VmPipeAddress) a; 132 if (localAddress == null || localAddress.getPort() == 0) { 133 localAddress = null; 134 for (int i = 10000; i < Integer.MAX_VALUE; i++) { 135 VmPipeAddress newLocalAddress = new VmPipeAddress(i); 136 if (!boundHandlers.containsKey(newLocalAddress) && !newLocalAddresses.contains(newLocalAddress)) { 137 localAddress = newLocalAddress; 138 break; 139 } 140 } 141 142 if (localAddress == null) { 143 throw new IOException("No port available."); 144 } 145 } else if (localAddress.getPort() < 0) { 146 throw new IOException("Bind port number must be 0 or above."); 147 } else if (boundHandlers.containsKey(localAddress)) { 148 throw new IOException("Address already bound: " + localAddress); 149 } 150 151 newLocalAddresses.add(localAddress); 152 } 153 154 for (SocketAddress a : newLocalAddresses) { 155 VmPipeAddress localAddress = (VmPipeAddress) a; 156 if (!boundHandlers.containsKey(localAddress)) { 157 boundHandlers.put(localAddress, new VmPipe(this, localAddress, getHandler(), getListeners())); 158 } else { 159 for (SocketAddress a2 : newLocalAddresses) { 160 boundHandlers.remove(a2); 161 } 162 throw new IOException("Duplicate local address: " + a); 163 } 164 } 165 } 166 167 return newLocalAddresses; 168 } 169 170 @Override 171 protected void unbind0(List<? extends SocketAddress> localAddresses) { 172 synchronized (boundHandlers) { 173 for (SocketAddress a : localAddresses) { 174 boundHandlers.remove(a); 175 } 176 } 177 } 178 179 /** 180 * {@inheritDoc} 181 */ 182 public IoSession newSession(SocketAddress remoteAddress, SocketAddress localAddress) { 183 throw new UnsupportedOperationException(); 184 } 185 186 void doFinishSessionInitialization(IoSession session, IoFuture future) { 187 initSession(session, future, null); 188 } 189}