/*
* IzPack - Copyright 2001-2009 Julien Ponge, All Rights Reserved.
*
* http://izpack.org/
* http://izpack.codehaus.org/
*
* Copyright 2009 Matthew Inger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.izforge.izpack.event;
import org.apache.bsf.BSFEngine;
import org.apache.bsf.BSFException;
import org.apache.bsf.BSFManager;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* Action which executes a BSF-supported script, which can specify the
* appropriate interface methods from the InstallerListener,
* and UninstallerListener as BSF methods.
*
* @author minger
*/
public class BSFAction extends ActionBase
{
private static final long serialVersionUID = 3258131345250005557L;
public static final String BSFACTIONS = "bsfactions";
public static final String BSFACTION = "bsfaction";
// PHASES NOT DEFINED IN ActionBase
public static final String BEFOREFILE = "beforefile";
public static final String AFTERFILE = "afterfile";
public static final String BEFOREDIR = "beforedir";
public static final String AFTERDIR = "afterdir";
public static final String BEFOREDELETE = "beforedelete";
public static final String AFTERDELETE = "afterdelete";
public static final String BEFOREDELETION = "beforedeletion";
public static final String AFTERDELETION = "afterdeletion";
private String script = null;
private String language = null;
private String scriptName = null;
private transient BSFManager manager = null;
private transient BSFEngine engine = null;
private static Map<String, MethodDescriptor> orderMethodMap = null;
private Properties variables = new Properties();
private static class MethodDescriptor
{
private String name;
private String argNames[];
public MethodDescriptor(String name, String[] argNames)
{
super();
this.name = name;
this.argNames = argNames;
}
}
private static interface MethodExistenceChecker
{
boolean isMethodDefined(String method, String scriptName, BSFEngine engine, BSFManager manager)
throws BSFException;
}
private static Map<String, MethodExistenceChecker> langToMethodCheckerMap = new HashMap<String, MethodExistenceChecker>();
static
{
orderMethodMap = new HashMap<String, MethodDescriptor>();
// UninstallerListener Methods
orderMethodMap.put(BSFAction.BEFOREDELETION,
new MethodDescriptor("beforeDeletion",
new String[]{"files", "handler"}));
orderMethodMap.put(BSFAction.AFTERDELETION,
new MethodDescriptor("afterDeletion",
new String[]{"files", "handler"}));
orderMethodMap.put(BSFAction.BEFOREDELETE,
new MethodDescriptor("beforeDelete",
new String[]{"file", "handler"}));
orderMethodMap.put(BSFAction.AFTERDELETE,
new MethodDescriptor("afterDelete",
new String[]{"file", "handler"}));
// InstallerListener Methods
orderMethodMap.put(BSFAction.BEFOREDIR,
new MethodDescriptor("beforeDir", new String[]{"file", "pack"}));
orderMethodMap.put(BSFAction.AFTERDIR,
new MethodDescriptor("afterDir", new String[]{"file", "pack"}));
orderMethodMap.put(BSFAction.BEFOREFILE,
new MethodDescriptor("beforeFile", new String[]{"file", "pack"}));
orderMethodMap.put(BSFAction.AFTERFILE,
new MethodDescriptor("afterFile", new String[]{"file", "pack"}));
orderMethodMap.put(BSFAction.BEFOREPACKS,
new MethodDescriptor("beforePacks", new String[]{"idata", "npacks", "handler"}));
orderMethodMap.put(BSFAction.AFTERPACKS,
new MethodDescriptor("afterPacks", new String[]{"idata", "handler"}));
orderMethodMap.put(BSFAction.BEFOREPACK,
new MethodDescriptor("beforePack", new String[]{"pack", "i", "handler"}));
orderMethodMap.put(BSFAction.AFTERPACK,
new MethodDescriptor("afterPack", new String[]{"pack", "i", "handler"}));
langToMethodCheckerMap.put("beanshell",
new MethodExistenceChecker()
{
public boolean isMethodDefined(String method, String scriptName, BSFEngine engine, BSFManager manager)
throws BSFException
{
String script = "this.namespace.getMethod(\"" + method + "\", new Class[0])";
Object res =
engine.eval(scriptName, 1, 1, script);
return res != null;
}
}
);
}
public BSFAction()
{
super();
}
public void setScript(String script)
{
this.script = script;
}
public String getScript()
{
return script;
}
public void setLanguage(String language)
{
this.language = language;
}
public void init() throws Exception
{
if (manager == null)
{
manager = new BSFManager();
}
if (engine == null)
{
engine = manager.loadScriptingEngine(language);
scriptName = "script." + language;
engine.exec(scriptName, 1, 1, script);
}
}
public void destroy() throws Exception
{
if (engine != null)
{
engine.terminate();
engine = null;
}
if (manager != null)
{
manager.terminate();
manager = null;
}
}
public void executeUninstall(String order, Object[] params) throws Exception
{
MethodDescriptor desc = orderMethodMap.get(order);
if (desc != null)
{
try
{
for (int i = 0; i < desc.argNames.length; i++)
{
if (params[i] != null)
{
manager.declareBean(desc.argNames[i],
params[i],
params[i].getClass());
}
}
manager.declareBean("variables", variables, Properties.class);
MethodExistenceChecker checker = langToMethodCheckerMap.get(language);
try
{
if (checker != null)
{
if (!checker.isMethodDefined(desc.name, scriptName, engine, manager))
{
return;
}
}
else
{
engine.eval(scriptName, 1, 1, desc.name);
}
}
catch (BSFException e)
{
e.printStackTrace();
return;
}
engine.exec(scriptName, 1, 1, desc.name + "()");
}
finally
{
if (desc.argNames != null)
{
for (int i = 0; i < desc.argNames.length; i++)
{
manager.undeclareBean(desc.argNames[i]);
}
}
manager.undeclareBean("variables");
}
}
}
public void execute(String order, Object[] params, Object idata) throws Exception
{
MethodDescriptor desc = orderMethodMap.get(order);
if (desc != null)
{
try
{
for (int i = 0; i < desc.argNames.length; i++)
{
if (params[i] != null)
{
manager.declareBean(desc.argNames[i],
params[i],
params[i].getClass());
}
}
Method m = null;
Class clazz = idata.getClass();
while (m == null && clazz != Object.class)
{
try
{
m = clazz.getDeclaredMethod("getVariables");
}
catch (NoSuchMethodException e)
{
clazz = clazz.getSuperclass();
}
}
if (m != null)
{
java.util.Properties properties = (java.util.Properties) m.invoke(idata);
variables.putAll(properties);
}
manager.declareBean("idata", idata, Class.forName("com.izforge.izpack.installer.AutomatedInstallData"));
MethodExistenceChecker checker = langToMethodCheckerMap.get(language);
try
{
if (checker != null)
{
if (!checker.isMethodDefined(desc.name, scriptName, engine, manager))
{
return;
}
}
else
{
engine.eval(scriptName, 1, 1, desc.name);
}
}
catch (BSFException e)
{
e.printStackTrace();
return;
}
engine.exec(scriptName, 1, 1, desc.name + "()");
}
finally
{
for (int i = 0; i < desc.argNames.length; i++)
{
manager.undeclareBean(desc.argNames[i]);
}
manager.undeclareBean("idata");
}
}
}
}