/*
* ALMA - Atacama Large Millimiter Array
* (c) European Southern Observatory, 2002
* Copyright by ESO (in the framework of the ALMA collaboration)
* and Cosylab 2002, All rights reserved
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package alma.acs.gui.util.panel;
import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.lang.reflect.Constructor;
import java.util.logging.Logger;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JRootPane;
import javax.swing.SwingUtilities;
import alma.acs.component.client.AdvancedComponentClient;
import alma.acs.container.ContainerServices;
import alma.acs.logging.AcsLogLevel;
/**
* The main frame of the application.
* It is the main window showing the panel inside.
*
* The panel must implement the IPanel interface and extend JComponent.
* It can also be a JRootPane in order to define its own menu bar.
*
* @author acaproni
*
*/
public class Frame extends JFrame {
public class FrameWindowListener extends WindowAdapter {
/**
* Signal the panel that the application is going to terminate
*
* @see WindowAdapter
*/
public void windowClosing(WindowEvent e) {
close();
}
/**
* Release the panel and terminate the application.
* The application has to terminate cleany without calling a
* System.exit. If it is not the case it mean that the panel still
* has some resource to release like a non daemon Thread or an open dialog
* or....
*
* @see WindowAdapter
*/
public void windowClosed(WindowEvent e) {
panel=null;
client=null;
contSvc=null;
logger=null;
windowListener=null;
}
}
// The panel shown in the window
private IPanel panel;
// The ACS client
private AdvancedComponentClient client=null;
// The logger
private Logger logger=null;
// The ContainerServices
private ContainerServices contSvc=null;
private FrameWindowListener windowListener = new FrameWindowListener();
/**
* Build the main window with the component inside.
*
* The main window catches window events in order to be able to
* close the panel before closing.
*
* @param params A string of paramters.
* The first parameter is the component to show in the window.
*
*/
public Frame(String[] params) throws PanelException {
if (params==null || params.length<0) {
throw new PanelException("Wrong params in constructor");
}
try {
connectACSComponentClient(params[0]);
panel = loadPanel(params[0]);
initialize(panel);
} catch (Throwable t) {
throw new PanelException("Error connecting the ACS component client",t);
}
addWindowListener(windowListener);
// Stert the panel
try {
panel.setACSContainerServices(contSvc);
panel.start();
} catch (Throwable t) {
throw new PanelException("Error starting IPanel "+params[0],t);
}
}
/**
* Init the GUI
*
* @param pnl The IPanel to show in the GUI
*/
private void initialize(IPanel pnl) throws PanelException {
if (pnl==null) {
throw new IllegalArgumentException("Invalid null IPanel content");
}
if (!(pnl instanceof JComponent)) {
throw new PanelException("The panel is not a JComponent");
}
if (pnl instanceof JRootPane) {
setContentPane((JRootPane)pnl);
} else {
add((JComponent)pnl, BorderLayout.CENTER);
}
pack();
setVisible(true);
}
/**
* Load the panel whose class name is in the parameter
*
* @param className The class name of the poanel to be shown
* in the main window
* @return A reference to the panel
*/
private IPanel loadPanel(String className) throws PanelException {
Thread t = Thread.currentThread();
ClassLoader loader = t.getContextClassLoader();
try {
Class cl =loader.loadClass(className);
Class[] classes = { JFrame.class };
Constructor constructor = cl.getConstructor(classes);
return (IPanel)constructor.newInstance((JFrame)this);
} catch (Throwable throwable) {
throwable.printStackTrace();
throw new PanelException("Error building "+className,throwable);
}
}
/**
* Print the usage message on the stdout
*
*@param cmd The name of the command
*/
public static void printUsage(String cmd) {
System.out.println("USAGE:");
System.out.println(cmd+" PanelClassName [params]");
System.out.println("Show a window with the panel inside.");
System.out.println("PanelClassName the name of the class implementing the panel");
System.out.println(" to show in the window");
System.out.println("params: a list of params to send to the panel, if present\n");
}
/**
* The starting point of the application: build the window
* and load the panel.
*
* @param args A list of params.
* The first parameter is the name of the panel
* to load.
*/
public static void main(String[] args) {
if (args.length==0) {
throw new IllegalArgumentException("Panel class name missing in args");
}
class LaunchThread extends Thread {
private String[] commandLineArgs;
public LaunchThread(String[] arguments) {
commandLineArgs=arguments;
}
public void run() {
try {
new Frame(commandLineArgs);
} catch (Throwable t) {
System.err.println(t.getMessage());
t.printStackTrace(System.err);
printUsage("PanelFrame");
String msg = "<HTML><BODY>Error opening panel: <I>"+t.getMessage();
msg+="</I><P>Is ACS running?";
JOptionPane.showMessageDialog(null, msg, "Error opening panel", JOptionPane.ERROR_MESSAGE);
System.exit(-1);
}
}
};
try {
SwingUtilities.invokeAndWait(new LaunchThread(args));
} catch (Throwable t) {
System.err.println(t.getMessage());
t.printStackTrace(System.err);
printUsage("PanelFrame");
System.exit(-1);
}
}
/**
* Connect to ACS as component client.
* It connects the client and the logger.
*
* @param className The name of the class of the panel to show in the frame
*
* @throws Exception In case of failure connecting to ACS
*/
private void connectACSComponentClient(String className) throws PanelException {
String[] tmp = className.split("\\.");
String clientName=tmp[tmp.length-1];
String managerLoc = System.getProperty("ACS.manager");
if (managerLoc!=null) {
managerLoc=managerLoc.trim();
} else {
throw new IllegalStateException("ACS.magager property not set!");
}
try {
client = new AdvancedComponentClient(null, managerLoc, clientName);
contSvc=client.getContainerServices();
logger = contSvc.getLogger();
logger.log(AcsLogLevel.DEBUG,"Connected to ACS");
setTitle(clientName);
} catch (Throwable t) {
if (logger!=null) {
logger.log(AcsLogLevel.ERROR,"Error connecting the simple client: "+t.getMessage());
} else {
System.err.println("Error connecting the simple client: "+t.getMessage());
}
client=null;
logger=null;
contSvc=null;
throw new PanelException("Error connetting ACS client",t);
}
}
/**
* Disconnect from ACS
*/
public void disconnectACSComponentClient() {
if (logger!=null) {
logger.log(AcsLogLevel.INFO,"Exiting from ACS");
}
try {
if (client!=null) {
client.tearDown();
}
} catch (Throwable e) {
System.err.println("Exception caught while releasing ACS: "+e.getMessage());
e.printStackTrace(System.err);
} finally {
logger=null;
client=null;
contSvc=null;
}
}
/**
* Release all the resources
* This is the last operation before closing
*/
private void close() {
Thread t = new Thread(new Runnable() {
public void run() {
if (logger!=null) {
logger.log(AcsLogLevel.DEBUG, "Closing");
}
try {
panel.stop();
} catch (Throwable t) {
// Ignore exceptions while closing
System.err.println("Exception caught while closing: "+t.getMessage());
t.printStackTrace(System.err);
}
if (logger!=null) {
logger.log(AcsLogLevel.DEBUG, "Releasing ACS client");
}
disconnectACSComponentClient();
System.out.println("Done.");
setVisible(false);
setRootPane(null);
removeWindowListener(windowListener);
dispose();
}
});
t.setDaemon(true);
t.setName("acsGUIUtil.Frame.close");
SwingUtilities.invokeLater(t);
}
}