Existem três threads clientes que enviam requisições para cada Objeto Servidor.
Cada Objeto Servidor tem três threads receptoras, cada uma responsável por atender a um cliente distinto. Observem que cada requisição é enviada para todos os três Objetos Servidores através das suas respectivas threads. Esse envio é feito através de um Pipe distinto, não compartilhado. Cada Objeto Servidor possui três métodos: depositar(double valor), retirar(double valor) e aplicarCorrecao(int percentagem), este último faz uma correção monetária sobre o valor
total da conta. Esses métodos são invocados, de forma concorrente, por cada thread no
Objeto Servidor i.
O saldo final em cada servidor devem ser iguais e o valor do saldo estão com uma diferença pequena, problema com os piped, as vezes a Thread de deposito realizar o deposto com o valor do saque e vice versa
Cliente Abstrato
package br.com.cliente;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PipedOutputStream;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Classe responsavel por enviar requisições ao servidor
*
* @author Filipe
*/
public abstract class AbstractClient extends Thread {
//Escritor para servidor 1
protected DataOutputStream out1;
//Escritor para servidor 2
protected DataOutputStream out2;
//Escritor para servidor 3
protected DataOutputStream out3;
protected Random random;
protected float value;
public AbstractClient(PipedOutputStream pOut1, PipedOutputStream pOut2, PipedOutputStream pOut3) {
this.random = new Random();
this.out1 = new DataOutputStream(pOut1);
this.out2 = new DataOutputStream(pOut2);
this.out3 = new DataOutputStream(pOut3);
}
/**
* Seta o valor da acao a ser escrita
*/
protected abstract void write();
@Override
public void run() {
try {
for (int i = 0; i < 9; i++) {
this.write(out1);
this.write(out2);
this.write(out3);
}
//feche os pipeds
out1.close();
out2.close();
out3.close();
} catch (IOException ex) {
Logger.getLogger(AbstractClient.class.getName()).log(Level.SEVERE, null, ex);
}
}
protected void write(DataOutputStream out) throws IOException {
//acao do cliente
write();
//cliente dispara acao
out.writeFloat(value);
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
Logger.getLogger(AbstractClient.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Enumerador para indicar qual o servidor deve-se enviar a informação
enum Operacao {
Server1(1), Server2(2), Server3(3);
public final int value;
Operacao(int value) {
this.value = value;
}
public static Operacao fromInteger(int x) {
switch (x) {
case 1:
return Server1;
case 2:
return Server2;
default:
return Server3;
}
}
}*/
}
Cliente Deposito
package br.com.cliente;
import br.com.server.Server;
import java.io.PipedOutputStream;
/**
* Thread para deposito
*
* @author Filipe
*/
public class ClientDeposito extends AbstractClient {
public ClientDeposito(PipedOutputStream pOut1, PipedOutputStream pOut2, PipedOutputStream pOut3) {
super(pOut1, pOut2, pOut3);
}
@Override
protected void write() {
this.value = Server.DEPOSITO;
}
}
Cliente Correção
package br.com.cliente;
import br.com.server.Server;
import java.io.PipedOutputStream;
/**
* Thread para Correcao
*
* @author Filipe
*/
public class ClientCorrecao extends AbstractClient {
public ClientCorrecao(PipedOutputStream pOut1, PipedOutputStream pOut2, PipedOutputStream pOut3) {
super(pOut1, pOut2, pOut3);
}
@Override
protected void write() {
this.value = Server.CORRECAO;
}
}
Cliente Saque
package br.com.cliente;
import br.com.server.Server;
import java.io.PipedOutputStream;
/**
* Thread para saque
*
* @author Filipe
*/
public class ClientSaque extends AbstractClient {
public ClientSaque(PipedOutputStream pOut1, PipedOutputStream pOut2, PipedOutputStream pOut3) {
super(pOut1, pOut2, pOut3);
}
@Override
protected void write() {
this.value = Server.SAQUE;
}
}
Receptor abstrato
package br.com.receptor;
import br.com.server.Server;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.PipedInputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Essa classe sera responsavel por enviar a informaçao ao servidor
*
* @author Filipe
*/
public abstract class AbstractReceptor extends Thread {
//Leitor
protected DataInputStream dIn;
protected final Server server;
public AbstractReceptor(PipedInputStream pis, Server server) {
this.dIn = new DataInputStream(pis);
this.server = server;
}
//Saque deposito ou correcao
public abstract void action(float value);
@Override
public void run() {
for (int i = 0; i < 9; i++) {
try {
//System.out.println("Aguardando ...");
//blocante
float valor = dIn.readFloat();
//acao do receptor
action(valor);
} catch (IOException ex) {
//if (!ex.getMessage().equals("Pipe closed")) {
Logger.getLogger(AbstractReceptor.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
Receptor Deposito
package br.com.receptor;
import java.io.PipedInputStream;
import br.com.server.Server;
/**
* Repassa o deposito pro valor pro servidor
*
*/
public class ReceptorDeposito extends AbstractReceptor {
public ReceptorDeposito(PipedInputStream pis, Server server) {
super(pis, server);
}
@Override
public void action(float value) {
System.out.println("Transferindo deposito: " + value);
if (server != null) {
this.server.depositar();
}
}
}
Receptor Saque
package br.com.receptor;
import java.io.PipedInputStream;
import br.com.server.Server;
public class ReceptorSaque extends AbstractReceptor {
public ReceptorSaque(PipedInputStream pis, Server server) {
super(pis, server);
}
@Override
public void action(float value) {
System.out.println("Sacando: " + value);
if (server != null) {
this.server.sacar();
}
}
}
Receptor Correção
package br.com.receptor;
import java.io.PipedInputStream;
import br.com.server.Server;
public class ReceptorCorrecao extends AbstractReceptor {
public ReceptorCorrecao(PipedInputStream pis, Server server) {
super(pis, server);
}
@Override
public void action(float value) {
if (server != null) {
System.out.println("Aplicando correção: " + value);
this.server.correcao();
}
}
}
Servidor
package br.com.server;
import br.com.receptor.ReceptorCorrecao;
import br.com.receptor.ReceptorDeposito;
import br.com.receptor.ReceptorSaque;
import java.io.PipedInputStream;
public class Server extends Thread {
/**
* Identificado para o servidor
*/
private static int ID = 1;
/**
* Salvo sera acessado simultaneamente entao preciso ler da memoria
* principal
*/
private final int id;
private volatile float saldo;
private ReceptorDeposito rdeposito;
private ReceptorSaque rsaque;
private ReceptorCorrecao rcorrecao;
public static final float SAQUE = 3;
public static final float DEPOSITO = 10;
public static final float CORRECAO = 0.1f;
public Server() {
this.saldo = 10;
this.id = ID;
ID++;
}
public Server(float saldo, PipedInputStream p1, PipedInputStream p2, PipedInputStream p3) {
this.saldo = saldo;
this.rdeposito = new ReceptorDeposito(p1, this);
this.rsaque = new ReceptorSaque(p2, this);
this.rcorrecao = new ReceptorCorrecao(p3, this);
this.id = ID;
ID++;
}
public Server(PipedInputStream p1, PipedInputStream p2, PipedInputStream p3) {
this(100, p1, p2, p3);
}
@Override
public void run() {
this.rdeposito.start();
this.rsaque.start();
this.rcorrecao.start();
}
public synchronized void depositar() {
System.out.println("Depositado: " + DEPOSITO + " no Servidor: " + id);
this.saldo += DEPOSITO;
}
public synchronized void sacar() {
System.out.println("Sacado: " + SAQUE + " no Servidor: " + id);
this.saldo -= SAQUE;
}
public synchronized void correcao() {
System.out.println("Correção aplicada: " + CORRECAO + " no Servidor: " + id);
this.saldo = saldo + (saldo * CORRECAO);
}
public float getSaldo() {
return saldo;
}
public void setSaldo(float saldo) {
this.saldo = saldo;
}
public boolean isAllAlive() {
return (rdeposito.isAlive()
|| rsaque.isAlive()
|| rcorrecao.isAlive());
}
@Override
public String toString() {
return "Server: " + id + " => Saldo: " + saldo;
}
}
Controller
package br.com.server;
import br.com.cliente.ClientCorrecao;
import br.com.cliente.ClientDeposito;
import br.com.cliente.ClientSaque;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* Classe que controla sincronismo com todos so servidores
*
* @author Filipe
*/
public class Controller {
private final List<Server> servers;
private boolean open;
public Controller() {
this.servers = new ArrayList<>();
}
public void runServer() {
init();
for (Server s : servers) {
while (s.isAllAlive()) {
//espera
}
}
System.out.println("SALDO FINAL");
for (Server s : servers) {
System.out.println(s);
}
}
/**
* Cria os piped out e in
*/
private void init() {
try {
//criando mensageiro para cliente enviar ao receptor
//criando canal de comunicao para receptor
//Server 1
PipedOutputStream s1out1 = new PipedOutputStream();
PipedInputStream s1in1 = new PipedInputStream(s1out1);
PipedOutputStream s1out2 = new PipedOutputStream();
PipedInputStream s1in2 = new PipedInputStream(s1out2);
PipedOutputStream s1out3 = new PipedOutputStream();
PipedInputStream s1in3 = new PipedInputStream(s1out3);
//Server 2
PipedOutputStream s2out1 = new PipedOutputStream();
PipedInputStream s2in1 = new PipedInputStream(s2out1);
PipedOutputStream s2out2 = new PipedOutputStream();
PipedInputStream s2in2 = new PipedInputStream(s2out2);
PipedOutputStream s2out3 = new PipedOutputStream();
PipedInputStream s2in3 = new PipedInputStream(s2out3);
//Server 3
PipedOutputStream s3out1 = new PipedOutputStream();
PipedInputStream s3in1 = new PipedInputStream(s3out1);
PipedOutputStream s3out2 = new PipedOutputStream();
PipedInputStream s3in2 = new PipedInputStream(s3out2);
PipedOutputStream s3out3 = new PipedOutputStream();
PipedInputStream s3in3 = new PipedInputStream(s3out3);
//cria o servidor com 3 receptores
//inicializa os receptores
Server server1 = new Server(100, s1in1, s1in2, s1in3);
this.servers.add(server1);
Server server2 = new Server(100, s2in1, s2in2, s2in3);
this.servers.add(server2);
Server server3 = new Server(100, s3in1, s3in2, s3in3);
this.servers.add(server3);
//clientes
new ClientDeposito(s1out1, s1out2, s1out3).start();
server1.start();
new ClientSaque(s2out1, s2out2, s2out3).start();
server2.start();
new ClientCorrecao(s3out1, s3out2, s3out3).start();
server3.start();
} catch (IOException ex) {
Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
}
}
public boolean isOpen() {
return open;
}
public void setOpen(boolean status) {
this.open = status;
}
}