/*
* File: Principal.java
*
*
* This file is a part of MICE, a program designed for
* people with severe motor disabilities to whom it is impossible
* to use a traditional mouse. This application gives these people
* the control of the physical mouse via another type of device.
*
* Authors: Isabel Gonzalez
* Date: 2008/ 2009
*
* Company: Colegio Publico de Educacion Especial Alborada, Zaragoza
* DIIS, Universidad de Zaragoza
*
* License: Copyright (C) 2008
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*
*
*/
package Pasarela;
import Pasarela.Interfaz.Pasarela2;
import java.awt.BorderLayout;
import java.io.*;
import java.lang.StringBuffer;
import java.nio.*;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.nio.charset.*;
import java.net.*;
import java.util.*;
import java.util.HashMap;
import java.lang.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import Pasarela.Interfaz.Pasarela2;
import Nucleo.*;
//Clase que recibe los codigos enviados por los drivers y los encamina hacia el Nucleo
public class Principal extends Thread {
public static Locale Idiomas; // idiomas de la aplicacion
private static final Principal INSTANCE = new Principal();
public Selector selector = null;
private int puerto_drivers = 17223;
private int puerto_nucleo = 17224;
private ServerSocketChannel driversChannel = null; // canal desde el que escuchara las conexiones de drivers
private ServerSocketChannel nucleoChannel = null; // canal desde el que escuchara las conexiones de núcleos
public static HashMap hashMap;
ChannelCallback instNucleo;
public static Pasarela2 pasarela;
private Principal() {
}
public static Principal getInstance() {
return INSTANCE;
}
// Inicializa los canales para recibir conexiones
public void inicializar() {
try {
selector = SelectorProvider.provider().openSelector();
// Inicializo serversocketchannel de drivers
driversChannel = ServerSocketChannel.open();
driversChannel.configureBlocking(false);
//InetAddress lh = InetAddress.getLocalHost();
//InetSocketAddress isa = new InetSocketAddress(lh, this.port );
InetSocketAddress isa = new InetSocketAddress(puerto_drivers);
driversChannel.socket().bind(isa);
// Inicializo serversocketchannel de nucleo
nucleoChannel = ServerSocketChannel.open();
nucleoChannel.configureBlocking(true);
InetSocketAddress isa2 = new InetSocketAddress(puerto_nucleo);
nucleoChannel.socket().bind(isa2);
// Registro el canal de drivers esperando un evento de conexion
driversChannel.register( this.selector, SelectionKey.OP_ACCEPT );
//nucleoChannel.register( this.selector, SelectionKey.OP_ACCEPT );
// Inicializo tabla hash donde guardara las instancias para la clase ChannelCallback
hashMap = new HashMap();
} catch (IOException ex) {
JOptionPane.showMessageDialog(pasarela, ResourceBundle.getBundle("idiomas.fich_idiomas",Idiomas).getString("strErrorInicializar"),
ResourceBundle.getBundle("idiomas.fich_idiomas",Idiomas).getString("strAviso"),
JOptionPane.ERROR_MESSAGE);
ex.printStackTrace();
System.exit(-1);
}
}
// Conecta el nucleo a la Pasarela, iniciando un nuevo thread de Núcleo
public void conectarNucleo() { // throws IOException, InterruptedException{
int localPort = nucleoChannel.socket().getLocalPort();
lanzarNucleo nucleo = new lanzarNucleo("Lanzo el nucleo");
nucleo.start();
SocketChannel channel;
try {
channel = nucleoChannel.accept();
channel.configureBlocking(false);
// registro un nuevo socket, esperando eventos de lectura
SelectionKey readKey = channel.register( this.selector, SelectionKey.OP_READ);//|SelectionKey.OP_WRITE );
ChannelCallback instcc=new ChannelCallback( channel, 0);
instNucleo=instcc;
readKey.attach(instcc);
//guardo la instancia del channelcallback
hashMap.put(instcc,1);
} catch (ClosedChannelException ex) {
JOptionPane.showMessageDialog(pasarela, ResourceBundle.getBundle("idiomas.fich_idiomas",Idiomas).getString("strErrorCanalCerradoNucleo"),
ResourceBundle.getBundle("idiomas.fich_idiomas",Idiomas).getString("strAviso"),
JOptionPane.ERROR_MESSAGE);
ex.printStackTrace();
System.exit(-1);
} catch (IOException ex) {
JOptionPane.showMessageDialog(pasarela, ResourceBundle.getBundle("idiomas.fich_idiomas",Idiomas).getString("strErrorConectarNucleo"),
ResourceBundle.getBundle("idiomas.fich_idiomas",Idiomas).getString("strAviso"),
JOptionPane.ERROR_MESSAGE);
ex.printStackTrace();
System.exit(-1);
}
}
// Conecta un nuevo Driver
public void conectarDriver(SelectionKey key)throws IOException, InterruptedException {
try {
ByteBuffer buffer = ByteBuffer.allocate(8);
IntBuffer intBuffer = buffer.asIntBuffer();
ServerSocketChannel nextReady = (ServerSocketChannel)key.channel();
int localPort = nextReady.socket().getLocalPort();
SocketChannel channel = nextReady.accept();
channel.configureBlocking( false );
ChannelCallback instcc=new ChannelCallback( channel, -1);
// primero lo configuro como bloqueante, para esperar el nombre del driver
instcc.channel.configureBlocking(true);
instcc.name= hashMap.size();
instcc.channel.configureBlocking( false );
// registro un nuevo socket, esperando eventos de lectura
SelectionKey readKey = channel.register( this.selector, SelectionKey.OP_READ);//|SelectionKey.OP_WRITE );
// almaceno el socket en la tabla hash
readKey.attach(instcc);
//guardo la instancia del channelcallback
hashMap.put(instcc,1);
} catch (ClosedChannelException ex) {
JOptionPane.showMessageDialog(pasarela, ResourceBundle.getBundle("idiomas.fich_idiomas",Idiomas).getString("strErrorCanalCerradoDriver"),
ResourceBundle.getBundle("idiomas.fich_idiomas",Idiomas).getString("strAviso"),
JOptionPane.ERROR_MESSAGE);
ex.printStackTrace();
}
catch (IOException ex) {
JOptionPane.showMessageDialog(pasarela, ResourceBundle.getBundle("idiomas.fich_idiomas",Idiomas).getString("strErrorConectarDriver"),
ResourceBundle.getBundle("idiomas.fich_idiomas",Idiomas).getString("strAviso"),
JOptionPane.ERROR_MESSAGE);
ex.printStackTrace();
}
}
// lee un evento del canal
public void leerDeCanal(SelectionKey key)throws IOException, InterruptedException {
ChannelCallback cc;
ByteBuffer buffer = ByteBuffer.allocate(8);
IntBuffer intBuffer = buffer.asIntBuffer();
ByteBuffer buffer2 = ByteBuffer.allocate(8);
IntBuffer intBuffer2 = buffer2.asIntBuffer();
buffer.clear();
SelectableChannel nextReady = (SelectableChannel) key.channel();
cc= (ChannelCallback)key.attachment();
if (!cc.channel.socket().isClosed()){
intBuffer=this.readMessage( (ChannelCallback) key.attachment() );
if ((intBuffer.get(0)!=-1)&&(intBuffer.get(1)!=-1)){
Iterator iterator = hashMap.keySet().iterator();
intBuffer2.put(intBuffer);
ChannelCallback instanciaActual=(ChannelCallback) key.attachment();
while( iterator.hasNext()) {
ChannelCallback x = (ChannelCallback)iterator.next();
if (x.getLocalPort()==instanciaActual.getLocalPort()){
//System.err.println("puertos iguales");
}
else{
if (!x.channel.socket().isClosed()){
writeMessage(x.channel,buffer2);
}
}
}
}
else{
desconectarSocket(1);
//this.desconectarTodosDrivers();
System.exit(0);
}
}
}
// Espera un evento de los registrados en el selector
public void esperarEvento() throws IOException, InterruptedException {
while (true){
int num = selector.select();
Iterator i = selector.selectedKeys().iterator();
while (i.hasNext()) {
SelectionKey key = (SelectionKey)i.next();
i.remove();
if ( key.isAcceptable() ) {
conectarDriver(key);
}
else if ( key.isReadable() ) {
leerDeCanal(key);
}
}
}
}
// Cierra los ServerSocketChannels de Núcleo y de los Drivers conectados
public void finalizar() throws IOException {
driversChannel.close();
nucleoChannel.close();
selector.close();
}
// Escribe un mensaje en el socket
public void writeMessage( SocketChannel channel, ByteBuffer message) throws IOException {
int nbytes = channel.write( message);
}
static final int BUFSIZE = 8;
// Decodifica un mensaje almacenado en un ByterBuffer. Devuelve su String correspondiente
public String decode( ByteBuffer byteBuffer ) throws CharacterCodingException {
Charset charset = Charset.forName( "us-ascii" );
CharsetDecoder decoder = charset.newDecoder();
CharBuffer charBuffer = decoder.decode( byteBuffer );
String result = charBuffer.toString();
return result;
}
// Lee un dato de un canal. Si el mensaje es "exit", cierra ese canal
public IntBuffer readMessage( ChannelCallback callback) throws IOException, InterruptedException {
ByteBuffer buffer = ByteBuffer.allocate(8);
IntBuffer intBuffer = buffer.asIntBuffer();
int nbytes = callback.getChannel().read(buffer);
buffer.flip();
if (intBuffer.get(0)==-1){
buffer.clear();
buffer.flip();
callback.getChannel().close();
hashMap.remove(callback);
try{
Socket s=callback.getChannel().socket();
if (s!=null){
s.close();
s=null;
}
} catch (IOException e1){
}
return(intBuffer);
}
return(intBuffer);
}
public int desconectarSocket(int nombreDriver){
Iterator it = hashMap.keySet().iterator();
ByteBuffer buffer = ByteBuffer.allocate(8);
IntBuffer intBuffer = buffer.asIntBuffer();
while( it.hasNext()) {
ChannelCallback x = (ChannelCallback)it.next();
if (x.name==nombreDriver){
try {
x.channel.close();
x.channel.socket().close();
hashMap.remove((ChannelCallback)x);
} catch (IOException ex) {
ex.printStackTrace();
}
return(1);
}
}
return(0);
}
public int desconectarTodosDrivers(){
ByteBuffer buffer = ByteBuffer.allocate(8);
IntBuffer intBuffer = buffer.asIntBuffer();
intBuffer.put(0,-1);
intBuffer.put(1,-1);
ChannelCallback ccnucleo=null;
Iterator it = hashMap.keySet().iterator();
while( it.hasNext()) {
ChannelCallback x = (ChannelCallback)it.next();
// nucleo
if (!(x.name==-1)){
try {
this.writeMessage(x.channel,buffer);
x.channel.close();
x.channel.socket().close();
//hashMap.remove((ChannelCallback)x);
} catch (IOException ex) {
ex.printStackTrace();
}
} else ccnucleo= (ChannelCallback) x;
}
hashMap.clear();
if (!ccnucleo.equals(null))
hashMap.put(ccnucleo,1);
return(1);
}
public static void main( String[] args ) {
Principal principal = Principal.getInstance();
Idiomas=Idiomas.getDefault();
pasarela= new Pasarela2();
pasarela.setVisible(true);
try {
principal.inicializar();
principal.conectarNucleo();
principal.esperarEvento();
} catch ( IOException e ) {
e.printStackTrace();
System.exit( -1 );
} catch ( InterruptedException e ) {
}
}
}
// Lanza una instacia del Nucleo en el mismo computador
class lanzarNucleo extends Thread {
public lanzarNucleo(String str) {
super(str);
}
public void run() { // Sobrecargando al metodo run
Nucleo n =new Nucleo();
n.conectarAPasarela();
n.esperarEventos();
}
}