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 Listmonitors = 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(Listmonitors) {
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 ListmonitorPlugins = 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