/*
* Copyright (C) 2004 The Concord Consortium, Inc.,
* 10 Concord Crossing, Concord, MA 01742
*
* Web Site: http://www.concord.org
* Email: info@concord.org
*
* 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
*
* END LICENSE */
package org.concord.otrunk.applet;
import java.applet.Applet;
import java.applet.AppletContext;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import org.concord.framework.otrunk.OTID;
import org.concord.framework.otrunk.OTObject;
import org.concord.framework.otrunk.OTrunk;
import org.concord.otrunk.datamodel.OTDatabase;
import org.concord.otrunk.view.OTViewContainerPanel;
import org.concord.otrunk.view.OTViewerHelper;
import org.concord.otrunk.xml.XMLDatabase;
public class OTAppletViewer extends JApplet
{
private static final long serialVersionUID = 1L;
protected OTViewerHelper viewerHelper;
protected boolean masterLoaded = false;
protected OTAppletViewer master;
protected Action stateAction;
protected JButton authorSaveButton;
private OTViewContainerPanel otContainer;
public OTAppletViewer()
{
super();
viewerHelper = new OTViewerHelper();
}
public String getAppletName()
{
return getParameter("name");
}
@Override
public void init()
{
super.init();
System.out.println("" + getAppletName() + " started init");
try{
// getCodeBase throws a security exception inside of MW
System.out.println("" + getAppletName() + " codebase: " + getCodeBase());
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void start()
{
super.start();
System.out.println("applet.start called on " + getAppletName());
if(isMaster()){
loadState();
}
if(isMasterLoaded()){
setupView();
}
if(isMaster()){
// The browser needs time to finish loading before we can find all the applets on the paqe
// so we sleep for a bit before looking for them.
// if there was some way to know when they had fully loaded. that should be used instead.
Thread delayer = new Thread(){
@Override
public void run()
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
AppletContext appletContext = getAppletContext();
if(appletContext == null){
// this should never be true but in MW there is no applet context
return;
}
// Go through all the applets on the page that are OTAppletViewerS and
// check if we are set to be their master. If so then notify them
// that we have finished loading.
Enumeration<Applet> applets = appletContext.getApplets();
while(applets.hasMoreElements()){
Applet a = applets.nextElement();
System.out.println("" + getAppletName() + " found: " + a.getParameter("name"));
if(a instanceof OTAppletViewer &&
!((OTAppletViewer)a).isMaster() &&
((OTAppletViewer)a).getMaster() == OTAppletViewer.this){
System.out.println("" + getAppletName() + " calling finishedLoading on " + a.getParameter("name"));
((OTAppletViewer)a).masterFinishedLoading(OTAppletViewer.this);
}
}
}
};
delayer.start();
}
}
/**
* There is also the stop method, but I believe that might be called if
*/
@Override
public void destroy()
{
System.out.println("applet.destroy called on " + getAppletName());
if(otContainer != null){
otContainer.setCurrentObject(null);
}
super.destroy();
}
@Override
public void stop()
{
System.out.println("applet.stop called on " + getAppletName());
super.stop();
}
protected URL getDatabaseURL()
{
String urlString = getParameter("url");
if (urlString != null && !urlString.equals("")){
try {
System.out.println(getAppletName() + " url " + urlString);
return new URL(getDocumentBase(), urlString);
} catch(MalformedURLException e){
e.printStackTrace();
}
}
String resourceString = getParameter("resource");
if (resourceString != null && !resourceString.equals("")){
System.out.println(getAppletName() + " resource " + resourceString);
return getClass().getResource(resourceString);
}
throw new RuntimeException("No url specified to load otml");
}
protected OTDatabase openOTDatabase() throws Exception
{
try {
URL url = getDatabaseURL();
return viewerHelper.loadOTDatabaseXML(url);
}catch (Exception ex) {
ex.printStackTrace();
throw ex;
}
}
protected void loadState()
{
try {
//Open xmlDB
OTDatabase otDB = openOTDatabase();
viewerHelper.loadOTrunk(otDB, this);
masterLoaded = true;
master = this;
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void setupView()
{
System.out.println("" + getAppletName() + " start setupView");
// get the otml url
try {
// look up view container with the frame.
otContainer = getViewerHelper().createViewContainerPanel();
getContentPane().setLayout(new BorderLayout());
getContentPane().removeAll();
getContentPane().add(otContainer, BorderLayout.CENTER);
// call setCurrentObject on that view container with a null
// frame
OTObject appletObject = getRootOTObject();
otContainer.setCurrentObject(appletObject);
///////////////////////////////
String saveUrlString = getParameter("author_state_save_url");
if (saveUrlString == null){
//Don't save
}
else{
stateAction = new StateHandlerAction();
//Save author content button
authorSaveButton = new JButton("Save");
authorSaveButton.setActionCommand("save_author");
authorSaveButton.addActionListener(stateAction);
JPanel buttonPanel = new JPanel();
buttonPanel.add(authorSaveButton);
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
}
///////////////////////////////
System.out.println("" + getAppletName() + " finished setupView");
//repaint();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public OTObject getRootOTObject()
throws Exception
{
// call setCurrentObject on that view container with a null
// frame
OTObject root = getViewerHelper().getRootObject();
String refid = getParameter("refid");
OTObject appletObject = root;
if(refid != null && refid.length() > 0){
appletObject = getOTObject(refid);
}
return appletObject;
}
public OTObject getOTObject(String otid) throws Exception {
OTID id = getID(otid);
return getOTrunk().getOTObject(id);
}
/**
* The applet is considered a master applet if it doesn't have master parameter
* pointing to another applet's name.
*
* @return
*/
public boolean isMaster()
{
// If the master field is set then we have already found our master
// so we don't need to check our parameters
if(master != null){
return master == this;
}
String masterName = getMasterName();
if(masterName != null){
return false;
}
return true;
}
public String getMasterName()
{
String masterString = getParameter("master");
if(masterString == null || masterString.equals("")){
return null;
}
return masterString;
}
public OTAppletViewer getMaster()
{
if(isMaster()){
return this;
}
if(master != null) {
return master;
}
String masterName = getMasterName();
if(masterName == null){
// we don't have a pointer to our master, and we are not a master ourselves
// this should never happen.
throw new RuntimeException("Non-master applet doesn't have a set master property");
}
Applet masterApplet = getAppletContext().getApplet(masterName);
if(masterApplet instanceof OTAppletViewer &&
((OTAppletViewer)masterApplet).isMaster()){
master = (OTAppletViewer)masterApplet;
return master;
}
// We did not find our master using that simple look up approach
// try manually going through all the applets
Enumeration<Applet> applets = getAppletContext().getApplets();
while(applets.hasMoreElements()){
Applet a = applets.nextElement();
System.out.println("" + getAppletName() + " found: " + a.getParameter("name"));
if(a instanceof OTAppletViewer){
OTAppletViewer sibbling = (OTAppletViewer)a;
if(sibbling.isMaster() &&
sibbling.getAppletName() != null &&
sibbling.getAppletName().equals(getMasterName())){
master = (OTAppletViewer)a;
return master;
}
}
}
return null;
}
public boolean isMasterLoaded()
{
if(isMaster()) {
return masterLoaded;
}
if(getMaster() != null){
return getMaster().isMasterLoaded();
}
return false;
}
public void masterFinishedLoading(OTAppletViewer master)
{
this.master = master;
//we might not be in the correct thread
SwingUtilities.invokeLater(new Runnable(){
public void run() {
setupView();
}
});
}
public OTViewerHelper getViewerHelper()
{
if(isMaster()) {
return viewerHelper;
}
// try to get the viewerHelper from the master applet
return getMaster().getViewerHelper();
}
public OTrunk getOTrunk()
{
if(isMaster()) {
return viewerHelper.getOtrunk();
}
return getMaster().getOTrunk();
}
public OTViewContainerPanel getOTContainer()
{
return otContainer;
}
public OTID getID(String id)
{
if(isMaster()){
if (id.startsWith("${")) {
// local id
id = id.substring(2, id.length()-1);
// FIXME it's not guaranteed that the db in viewerHelper is the db that contains this local id
return ((XMLDatabase)viewerHelper.getOtDB()).getOTIDFromLocalID(id);
} else {
// assume its a uuid or path id
return getOTrunk().getOTID(id);
}
}
OTAppletViewer localMaster = getMaster();
if(localMaster == null){
return null;
}
return localMaster.getID(id);
}
public void saveAuthorState()
{
String saveUrlString = getParameter("author_state_save_url");
if (saveUrlString == null){
//Don't save
System.err.println("No author url specified for saving");
return;
}
try{
System.out.println("opening "+saveUrlString);
URL saveUrl = new URL(getDocumentBase(), saveUrlString);
OTDatabase otDB = viewerHelper.getOtDB();
String method = getParameter("author_state_save_method");
if(method == null || method.length() == 0) {
method = "PUT";
}
viewerHelper.saveOTDatabaseXML(otDB, saveUrl, method);
}
catch (Exception ex) {
ex.printStackTrace();
}
}
class StateHandlerAction extends AbstractAction
{
/**
* This is not intended to be serialized, but this removes the warnings
*/
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e)
{
if (e.getActionCommand().equals("save_author")){
saveAuthorState();
}
}
}
}