/**
*Copyright [2009-2010] [dennis zhuang]
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*Unless required by applicable law or agreed to in writing,
*software distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
*either express or implied. See the License for the specific language governing permissions and limitations under the License
*/
package com.google.code.hs4j.network.nio.impl;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.util.Queue;
import com.google.code.hs4j.network.config.Configuration;
import com.google.code.hs4j.network.core.CodecFactory;
import com.google.code.hs4j.network.core.Handler;
import com.google.code.hs4j.network.core.Session;
import com.google.code.hs4j.network.core.WriteMessage;
import com.google.code.hs4j.network.core.impl.AbstractController;
import com.google.code.hs4j.network.nio.NioSessionConfig;
import com.google.code.hs4j.network.nio.SelectionKeyHandler;
import com.google.code.hs4j.network.util.SystemUtils;
/**
* Base nio controller
*
* @author dennis
*
*/
public abstract class NioController extends AbstractController implements
SelectionKeyHandler {
protected SelectorManager selectorManager;
/**
* Reactor count
*/
protected int selectorPoolSize = SystemUtils.getSystemThreadCount();
/**
* @see setSelectorPoolSize
* @return
*/
public int getSelectorPoolSize() {
return this.selectorPoolSize;
}
public void setSelectorPoolSize(int selectorPoolSize) {
if (isStarted()) {
throw new IllegalStateException("Controller has been started");
}
this.selectorPoolSize = selectorPoolSize;
}
public NioController() {
super();
}
public NioController(Configuration configuration, CodecFactory codecFactory) {
super(configuration, codecFactory);
}
public NioController(Configuration configuration, Handler handler,
CodecFactory codecFactory) {
super(configuration, handler, codecFactory);
}
public NioController(Configuration configuration) {
super(configuration);
}
/**
* Write task
*
* @author dennis
*
*/
private final class WriteTask implements Runnable {
private final SelectionKey key;
private WriteTask(SelectionKey key) {
this.key = key;
}
public final void run() {
dispatchWriteEvent(this.key);
}
}
/**
* Read task
*
* @author dennis
*
*/
private final class ReadTask implements Runnable {
private final SelectionKey key;
private ReadTask(SelectionKey key) {
this.key = key;
}
public final void run() {
dispatchReadEvent(this.key);
}
}
public final SelectorManager getSelectorManager() {
return this.selectorManager;
}
@Override
protected void start0() throws IOException {
try {
initialSelectorManager();
doStart();
} catch (IOException e) {
log.error("Start server error", e);
notifyException(e);
stop();
throw e;
}
}
/**
* Start selector manager
*
* @throws IOException
*/
protected void initialSelectorManager() throws IOException {
if (this.selectorManager == null) {
this.selectorManager = new SelectorManager(this.selectorPoolSize, this,
this.configuration);
this.selectorManager.start();
}
}
/**
* Inner startup
*
* @throws IOException
*/
protected abstract void doStart() throws IOException;
/**
* Read event occured
*/
public void onRead(SelectionKey key) {
if (this.readEventDispatcher == null) {
dispatchReadEvent(key);
} else {
this.readEventDispatcher.dispatch(new ReadTask(key));
}
}
/**
* Writable event occured
*/
public void onWrite(final SelectionKey key) {
if (this.writeEventDispatcher == null) {
dispatchWriteEvent(key);
} else {
this.writeEventDispatcher.dispatch(new WriteTask(key));
}
}
/**
* Cancel selection key
*/
public void closeSelectionKey(SelectionKey key) {
if (key.attachment() instanceof Session) {
Session session = (Session) key.attachment();
if (session != null) {
session.close();
}
}
}
/**
* Dispatch read event
*
* @param key
* @return
*/
protected abstract void dispatchReadEvent(final SelectionKey key);
/**
* Dispatch write event
*
* @param key
* @return
*/
protected abstract void dispatchWriteEvent(final SelectionKey key);
@Override
protected void stop0() throws IOException {
if (this.selectorManager == null || !this.selectorManager.isStarted()) {
return;
}
this.selectorManager.stop();
}
public synchronized void bind(int port) throws IOException {
if (isStarted()) {
throw new IllegalStateException("Server has been bind to "
+ getLocalSocketAddress());
}
bind(new InetSocketAddress(port));
}
/**
* Build nio session config
*
* @param sc
* @param queue
* @return
*/
protected final NioSessionConfig buildSessionConfig(SelectableChannel sc,
Queue<WriteMessage> queue) {
final NioSessionConfig sessionConfig = new NioSessionConfig(sc,
getHandler(), this.selectorManager, getCodecFactory(),
getStatistics(), queue, this.dispatchMessageDispatcher,
isHandleReadWriteConcurrently(), this.sessionTimeout, this.configuration
.getSessionIdleTimeout());
return sessionConfig;
}
}