Originariamente inviato da stprogramming
In linea di massima ho pensato di utilizzare la reflection e di raggruppare delle classi in file .jar..
Secondo te è giusto questo approccio?
La reflection è, per forza di cose, necessaria (anche se veramente al minimo). Andiamo con ordine:
1) I plug-in devono essere "scoperti". È la applicazione che "sa" dove devono/possono stare i jar dei plug-in. Per scansionare la/e directory è sufficiente che la applicazione usi i ben noti metodi in java.io.File. Se hai anche solo un minimo di esperienza su Java non credo che devo spiegarti questo punto.
Che comunque è il problema assolutamente minore.
2) Quando la applicazione trova un jar di plug-in deve poter ottenere una serie di informazioni. Sicuramente, come minimo, un nome di classe da caricare. Imporre nomi di classi/package ovviamente non è una buona cosa. In genere è sufficiente stabilire che dentro un jar ci sia un file "descrittore" che descrive il plug-in. File di properties, xml, altro ... qualunque cosa va bene, purché sia chiaro a chi sviluppa l'applicazione e a chi sviluppa un plug-in. Può contenere nome del plug-in, autore/i, nome della classe principale da caricare e magari altro. Anche il "manifest" che è contenuto in tutti i jar potrebbe andare bene.
3) Si deve fare in modo che il jar sia utilizzabile dalla JVM, si presuppone che non sia già "in classpath" (anche se si potrebbe lanciare la applicazione Java con un batch/script o eseguibile nativo che fanno la ricerca e predispongono il classpath per l'avvio della JVM).
Comunque a parte scenari particolari, esiste una classe particolare che si può utilizzare: java.net.URLClassLoader
È un classloader che è in grado di caricare classi/risorse da URL che fanno riferimento a jar o directory. Quando parlo di URL non pensare solo alla "rete", un file su file-system può essere rappresentato da un URL file:// ...
4) Tra applicazione e plug-in deve esserci un "contratto" ben preciso. E quando parlo di "contratto" probabilmente hai già idea: interfacce (o al limite classi astratte). La applicazione caricherà una classe, non importa tanto come si chiama, l'importante è che implementi qualcosa di "noto" alla applicazione.
Supponiamo: la classe principale del plug-in deve implementare una interfaccia fornita dalla applicazione:
codice:
public interface PluginStarter {
void setupPlugin(PluginContext ctx);
}
setupPlugin verrà invocato dalla applicazione, passando un oggetto PluginContext (interfaccia della applicazione).
Supponiamo: in una applicazione "grafica" un plug-in ha la facoltà di aggiungere una o più voci di menù sotto un menù fisso/noto solo alla applicazione. Questa capacità deve essere "esposta" verso il plug-in. PluginContext potrebbe quindi essere:
codice:
public interface PluginContext {
void addMenuItem(PluginMenuItem menuItem, PluginMenuListener listener);
}
PluginMenuItem (sempre dalla applicazione) potrebbe contenere label, icona (e altro) relativo alla voce di menù per il plug-in.
Il plug-in quindi invoca addMenuItem passando i dati del menù e un listener, che avrà un metodo per segnalare la invocazione del menù. Non sto a postare la definizione ... potrebbe essere simile ad ActionListener.
Ti chiederai: perché non ho usato allora JMenuItem e ActionListener? Beh, così almeno il plug-in non è "accoppiato" ad AWT/Swing, insomma è slegato dal framework grafico usato dalla applicazione!
Finisco qui. Una volta che la applicazione "sa" qualcosa del plug-in e una volta che quest'ultimo "sa" qualcosa della applicazione e può invocare qualcosa .... sta solo a te e alla tua fantasia fare il resto ...