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.socket.nio;
021
022import java.io.IOException;
023import java.net.InetSocketAddress;
024import java.net.SocketAddress;
025import java.nio.channels.DatagramChannel;
026import java.util.Collections;
027import java.util.Iterator;
028import java.util.concurrent.Executor;
029
030import org.apache.mina.core.polling.AbstractPollingIoConnector;
031import org.apache.mina.core.service.IoConnector;
032import org.apache.mina.core.service.IoProcessor;
033import org.apache.mina.core.service.SimpleIoProcessorPool;
034import org.apache.mina.core.service.TransportMetadata;
035import org.apache.mina.transport.socket.DatagramConnector;
036import org.apache.mina.transport.socket.DatagramSessionConfig;
037import org.apache.mina.transport.socket.DefaultDatagramSessionConfig;
038
039/**
040 * {@link IoConnector} for datagram transport (UDP/IP).
041 *
042 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
043 */
044public final class NioDatagramConnector extends AbstractPollingIoConnector<NioSession, DatagramChannel> implements
045DatagramConnector {
046
047    /**
048     * Creates a new instance.
049     */
050    public NioDatagramConnector() {
051        super(new DefaultDatagramSessionConfig(), NioProcessor.class);
052    }
053
054    /**
055     * Creates a new instance.
056     * 
057     * @param processorCount The number of IoProcessor instance to create
058     */
059    public NioDatagramConnector(int processorCount) {
060        super(new DefaultDatagramSessionConfig(), NioProcessor.class, processorCount);
061    }
062
063    /**
064     * Creates a new instance.
065     * 
066     * @param processor The IoProcessor instance to use
067     */
068    public NioDatagramConnector(IoProcessor<NioSession> processor) {
069        super(new DefaultDatagramSessionConfig(), processor);
070    }
071
072    /**
073     * Constructor for {@link NioDatagramConnector} with default configuration which will use a built-in
074     * thread pool executor to manage the given number of processor instances. The processor class must have
075     * a constructor that accepts ExecutorService or Executor as its single argument, or, failing that, a
076     * no-arg constructor.
077     * 
078     * @param processorClass the processor class.
079     * @param processorCount the number of processors to instantiate.
080     * @see SimpleIoProcessorPool#SimpleIoProcessorPool(Class, Executor, int, java.nio.channels.spi.SelectorProvider)
081     * @since 2.0.0-M4
082     */
083    public NioDatagramConnector(Class<? extends IoProcessor<NioSession>> processorClass, int processorCount) {
084        super(new DefaultDatagramSessionConfig(), processorClass, processorCount);
085    }
086
087    /**
088     * Constructor for {@link NioDatagramConnector} with default configuration with default configuration which will use a built-in
089     * thread pool executor to manage the default number of processor instances. The processor class must have
090     * a constructor that accepts ExecutorService or Executor as its single argument, or, failing that, a
091     * no-arg constructor. The default number of instances is equal to the number of processor cores
092     * in the system, plus one.
093     * 
094     * @param processorClass the processor class.
095     * @see SimpleIoProcessorPool#SimpleIoProcessorPool(Class, Executor, int, java.nio.channels.spi.SelectorProvider)
096     * @see org.apache.mina.core.service.SimpleIoProcessorPool#DEFAULT_SIZE
097     * @since 2.0.0-M4
098     */
099    public NioDatagramConnector(Class<? extends IoProcessor<NioSession>> processorClass) {
100        super(new DefaultDatagramSessionConfig(), processorClass);
101    }
102
103    public TransportMetadata getTransportMetadata() {
104        return NioDatagramSession.METADATA;
105    }
106
107    public DatagramSessionConfig getSessionConfig() {
108        return (DatagramSessionConfig) sessionConfig;
109    }
110
111    @Override
112    public InetSocketAddress getDefaultRemoteAddress() {
113        return (InetSocketAddress) super.getDefaultRemoteAddress();
114    }
115
116    public void setDefaultRemoteAddress(InetSocketAddress defaultRemoteAddress) {
117        super.setDefaultRemoteAddress(defaultRemoteAddress);
118    }
119
120    @Override
121    protected void init() throws Exception {
122        // Do nothing
123    }
124
125    @Override
126    protected DatagramChannel newHandle(SocketAddress localAddress) throws Exception {
127        DatagramChannel ch = DatagramChannel.open();
128
129        try {
130            if (localAddress != null) {
131                try {
132                    ch.socket().bind(localAddress);
133                    setDefaultLocalAddress(localAddress);
134                } catch (IOException ioe) {
135                    // Add some info regarding the address we try to bind to the
136                    // message
137                    String newMessage = "Error while binding on " + localAddress + "\n" + "original message : "
138                            + ioe.getMessage();
139                    Exception e = new IOException(newMessage);
140                    e.initCause(ioe.getCause());
141
142                    // and close the channel
143                    ch.close();
144
145                    throw e;
146                }
147            }
148
149            return ch;
150        } catch (Exception e) {
151            // If we got an exception while binding the datagram,
152            // we have to close it otherwise we will loose an handle
153            ch.close();
154            throw e;
155        }
156    }
157
158    @Override
159    protected boolean connect(DatagramChannel handle, SocketAddress remoteAddress) throws Exception {
160        handle.connect(remoteAddress);
161        return true;
162    }
163
164    @Override
165    protected NioSession newSession(IoProcessor<NioSession> processor, DatagramChannel handle) {
166        NioSession session = new NioDatagramSession(this, handle, processor);
167        session.getConfig().setAll(getSessionConfig());
168        return session;
169    }
170
171    @Override
172    protected void close(DatagramChannel handle) throws Exception {
173        handle.disconnect();
174        handle.close();
175    }
176
177    // Unused extension points.
178    @Override
179    @SuppressWarnings("unchecked")
180    protected Iterator<DatagramChannel> allHandles() {
181        return Collections.EMPTY_LIST.iterator();
182    }
183
184    @Override
185    protected ConnectionRequest getConnectionRequest(DatagramChannel handle) {
186        throw new UnsupportedOperationException();
187    }
188
189    @Override
190    protected void destroy() throws Exception {
191        // Do nothing
192    }
193
194    @Override
195    protected boolean finishConnect(DatagramChannel handle) throws Exception {
196        throw new UnsupportedOperationException();
197    }
198
199    @Override
200    protected void register(DatagramChannel handle, ConnectionRequest request) throws Exception {
201        throw new UnsupportedOperationException();
202    }
203
204    @Override
205    protected int select(int timeout) throws Exception {
206        return 0;
207    }
208
209    @Override
210    @SuppressWarnings("unchecked")
211    protected Iterator<DatagramChannel> selectedHandles() {
212        return Collections.EMPTY_LIST.iterator();
213    }
214
215    @Override
216    protected void wakeup() {
217        // Do nothing
218    }
219}