segunda-feira, 26 de janeiro de 2009

Mais Threads, ClassLoader, Classpath, Arquitetura de Plug-ins, Interfaces e mais recursos Java - PARTE 1.

O problema é interceptar determinados eventos em um servidor de download para tarifação em tempo real em um servidor de tarifação. O servidor de download permite a instalação de plug-ins escritos em Java para interceptar os eventos de download.

Esses eventos são disparados no ciclo do download, e são os seguintes: solicitação de download, download iniciado, download terminado com sucesso, download cancelado.

A classe Java não deve sobrecarregar o servidor para não causar indisponibilidade do serviço. Se a tarifação não puder ser efetuada o download não pode ser interrompido.

O problema é conectar o sistema de tarifação ao sistema de download.

Interface Java que deve ser implementada para interceptar os eventos:

public interface MonitorPlugin {

public void downloadRequested(Download download);

public void downloadStarted(Download download);

public void downloadFinished(Download download);

public void downloadCanceled(Download download);
}


A classe Java deve estar dentro do pacote padrão (sem pacote) dentro de um JAR com o mesmo nome no diretório raiz da aplicação.


Exemplo:
import downloadserver.Download;
import downloadserver.MonitorPlugin;

public class MonitorPluginSOP implements MonitorPlugin {

public void downloadRequested(Download download) {
System.out.println("downloadRequested T:" + download.getThreadId() + " U:" + download.getUserId());
}

public void downloadStarted(Download download) {
System.out.println("downloadStarted T:" + download.getThreadId() + " U:" + download.getUserId());
}

public void downloadFinished(Download download) {
System.out.println("downloadFinished T:" + download.getThreadId() + " U:" + download.getUserId());
}

public void downloadCanceled(Download download) {
System.out.println("downloadCanceled T:" + download.getThreadId() + " U:" + download.getUserId());
}

}


A classe MonitorPluginSOP vai estar dentro do JAR MonitorPluginSOP.jar.

O sistema de tarifação possui os comandos de tarifação e estorno. Para tarifação e estorno devem ser informados o numero de identificação do cliente, o comando e o serviço a ser tarifado.

Vamos discutir mais sobre o sistema de tarifação e o plug-in que fará a conexão entre os servidores no próximo post.

Por enquanto vamos ver o servidor de download que é uma simulação de um servidor real.

A classe que representa um download é a seguinte:
package downloadserver;

import java.util.ArrayList;
import java.util.List;

/*
* A classe Download implementa Runnable para possuir o comportamento de uma
* Thread. Para dar a possibilidade de parar a execução a classe possui
* um atributo running, quando running igual a false o objeto para a sua
* execução. O atributo running é alterado através do método cancel.
*/
public class Download implements Runnable {

static private long threadCount = 0;
static public final long DOWNLOAD_SIZE = 16;
private long threadId;
private long bytesSent = 0;
private int userId;
private boolean running = true;
private List monitors = new ArrayList();

public Download() {
threadId = threadCount++;
}

public Download(int userId) {
this.userId = userId;
threadId = threadCount++;
}

public void setUserId(int userId) {
this.userId = userId;
}

public int getUserId() {
return userId;
}

public long getThreadId() {
return threadId;
}

public long getBytesSent() {
return bytesSent;
}

public void request() {
downloadRequested();
}

public void cancel() {
running = false;
}

public void addMonitor(MonitorPlugin monitor) {
monitors.add(monitor);
}

public void addMonitor(List monitors) {
this.monitors.addAll(monitors);
}

private void downloadRequested() {
for (MonitorPlugin m : monitors) {
m.downloadRequested(this);
}
}

private void downloadStarted() {
for (MonitorPlugin m : monitors) {
m.downloadStarted(this);
}
}

private void downloadFinished() {
for (MonitorPlugin m : monitors) {
m.downloadFinished(this);
}
}

private void downloadCanceled() {
for (MonitorPlugin m : monitors) {
m.downloadCanceled(this);
}
}

public void run() {
downloadStarted();
while (running && bytesSent < DOWNLOAD_SIZE) {
bytesSent++;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (bytesSent == DOWNLOAD_SIZE) {
downloadFinished();
} else {
downloadCanceled();
}
}
}


E a classe que representa o Servidor é a seguinte, a classe está comentada nos seus principais recursos:
package downloadserver;

import java.io.File;
import java.io.FilenameFilter;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;

public class Server extends javax.swing.JFrame {

private int usersCount = 0;
private List monitorPlugins = new ArrayList();

public Server() {
initComponents();
loadMonitorPlugin();
inicia();
}

@SuppressWarnings("unchecked")
//
private void initComponents() {

jButton2 = new javax.swing.JButton();

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("Server");
setBounds(new java.awt.Rectangle(0, 0, 100, 500));
getContentPane().setLayout(new java.awt.FlowLayout());

jButton2.setText("Novo");
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton2ActionPerformed(evt);
}
});
getContentPane().add(jButton2);
}//


private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
novo();
}

/*
* Lê os arquivos de plug-in sem a necessidade de estarem no classepath.
*/
public void loadMonitorPlugin() {

try {
File dir = new File(".");
String[] children;
FilenameFilter filter = new FilenameFilter() {

public boolean accept(File dir, String name) {
return name.endsWith(".jar");
}
};
children = dir.list(filter);
if (children != null) {
for (int i = 0; i < children.length; i++) {
String filename = children[i];
try {
String classname = filename.replaceAll("[.]jar", "");

java.io.File file = new java.io.File(filename);
java.net.URL url = file.toURI().toURL();
URL[] urls = new URL[]{url};

ClassLoader loader = URLClassLoader.newInstance(urls, this.getClass().getClassLoader());

Class clazz = loader.loadClass(classname);
MonitorPlugin mp = (MonitorPlugin) clazz.newInstance();
monitorPlugins.add(mp);

System.out.println("Adicionada: " + classname);

} catch (Exception ex) {
ex.printStackTrace();
}
}
}

} catch (Exception ex) {
ex.printStackTrace();
}
}

/*
* Cria um novo download e exibe na tela como um botão. Ao clicar no botão o download é cancelado.
*/
private void novo() {
Download d = new Download(usersCount++);
d.addMonitor(monitorPlugins);
d.request();
print(d);
new Thread(d).start();
}


/*
* Executado no início cria 5 novos downloads.
*/
public void inicia() {
for (int i = 0; i < 5; i++) {
novo();
}
}

/*
* Exibe um download na tela como um botão, adiciona um ouvinte (monitor)
* ao download para atualizar a interface e adiciona ao evento de click
* a operação de cancelar o download.
*/
private void print(final Download d) {
final JButton elementoGrafico = new JButton();
elementoGrafico.setText("T:" + d.getThreadId() + " U:" + d.getUserId());
getContentPane().add(elementoGrafico);

elementoGrafico.addMouseListener(new java.awt.event.MouseAdapter() {

@Override
public void mouseClicked(java.awt.event.MouseEvent evt) {
d.cancel();
}
});

d.addMonitor(
new MonitorPlugin() {

public void downloadRequested(Download download) {
}

public void downloadStarted(Download download) {
}

public void downloadFinished(Download download) {
elementoGrafico.setBackground(new java.awt.Color(51, 204, 0));
}

public void downloadCanceled(Download download) {
elementoGrafico.setBackground(new java.awt.Color(255, 0, 51));
}
});
setVisible(true);
}

public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {

public void run() {
new Server().setVisible(true);
}
});
}

// Variables declaration - do not modify
private javax.swing.JButton jButton2;
// End of variables declaration
}


Bem, é isso. Vou tentar postar a continuação o mais breve possível.

O arquivo para download.

Abraços, Rodrigo Alencar.

Nenhum comentário:

Postar um comentário

 
BlogBlogs.Com.Br