/*
* #!
* Ontopia Webed
* #-
* Copyright (C) 2001 - 2013 The Ontopia Project
* #-
* 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 net.ontopia.topicmaps.webed.impl.utils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import net.ontopia.topicmaps.webed.core.ActionIF;
import net.ontopia.topicmaps.webed.impl.basic.ActionForwardPage;
import net.ontopia.topicmaps.webed.impl.basic.ActionForwardPageIF;
import net.ontopia.topicmaps.webed.impl.basic.ActionGroup;
import net.ontopia.topicmaps.webed.impl.basic.ActionGroupIF;
import net.ontopia.topicmaps.webed.impl.basic.ActionInGroup;
import net.ontopia.topicmaps.webed.impl.basic.ActionRegistry;
import net.ontopia.topicmaps.webed.impl.basic.ActionRegistryIF;
import net.ontopia.topicmaps.webed.impl.basic.Constants;
import net.ontopia.topicmaps.webed.impl.basic.FieldInformation;
import net.ontopia.topicmaps.webed.impl.basic.FieldInformationIF;
import net.ontopia.topicmaps.webed.impl.basic.ImageInformation;
import net.ontopia.topicmaps.webed.impl.basic.ImageInformationIF;
import net.ontopia.topicmaps.webed.impl.basic.ParamRuleIF;
import net.ontopia.utils.OntopiaRuntimeException;
import net.ontopia.xml.SAXTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
/**
* INTERNAL: Parse an XML instance which stores information about the
* action configuration which builds up basically action groups hold
* inside a so-called action registry.
* <p>
* Note: Assumes a well-formed and valid XML instance according the DTD.
*/
public class ActionConfigContentHandler extends SAXTracker {
// --- define a logging category.
static Logger log = LoggerFactory.getLogger(ActionConfigContentHandler.class.getName());
// --- global storage
ActionRegistryIF registry;
String contextPath;
// --- helper variables while processing
String currentActionType;
ActionForwardPageIF currentForwardPage;
String currentForwardName;
String currentForwardType;
String currentActionName;
String currentActionClass;
String currentActionExclusive;
ActionGroupIF currentActionGroup;
// key: shortName, value: FQCN
Map classMap;
// key: forwardName, value: ForwardPageResponseComposite
Map globalForwards;
// key: forwardName, value: ForwardPageResponseComposite
Map currentForwards;
// key: ActionInGroup, value: ForwardPageResponseComposite
Map currentForwardRules;
// key: actionName, value: ActionInGroup
Map currentActions;
// key: Class, value: ActionIF
Map actionCache;
/**
* default constructor.
*/
public ActionConfigContentHandler(String contextPath) {
this.contextPath = contextPath;
this.actionCache = new HashMap();
this.registry = new ActionRegistry();
}
/**
* Gets the action registry object.
*/
public ActionRegistryIF getRegistry() {
return registry;
}
// --------------------------------------------------------------
// override methods from SAXTracker
// --------------------------------------------------------------
public void startElement(String nsuri, String lname, String qname,
Attributes attrs) {
try {
// ==== classMap ========================================
if (lname == "classMap") {
classMap = new HashMap();
} // ----------------------------------------------------
else if (lname == "class") {
String shortcut = attrs.getValue("", "shortcut");
String fullname = attrs.getValue("", "fullname");
classMap.put(shortcut, fullname);
} // === buttonMap ======================================
else if (lname == "image") {
String name = attrs.getValue("", "name");
// generate a absolute path regarding to the web application or use the absolute src if provided.
String src = attrs.getValue("", "absolutesrc");
if (src == null) src = contextPath + attrs.getValue("", "src");
String width = attrs.getValue("", "width");
String height = attrs.getValue("", "height");
String border = attrs.getValue("", "border");
String align = attrs.getValue("", "align");
ImageInformationIF img = new ImageInformation(name, src, width,
height, border, align);
registry.addImage(img);
} // ==== fieldMap ======================================
else if (lname == "field") {
String name = attrs.getValue("", "name");
String type = attrs.getValue("", "type");
String maxlength = attrs.getValue("", "maxlength");
String columns = attrs.getValue("", "columns");
String rows = attrs.getValue("", "rows");
FieldInformationIF field = new FieldInformation(name, type, maxlength,
columns, rows);
registry.addField(field);
} // ==== globalForwards ================================
else if (lname == "globalForwards") {
globalForwards = new HashMap();
} // ----------------------------------------------------
// also allowed as element in actionGroup
else if (lname == "forward") {
// --- required
currentForwardName = attrs.getValue("", "name");
String path = attrs.getValue("", "path");
// --- optional
// type: success|failure|all(default)
currentForwardType = attrs.getValue("", "type");
if (currentForwardType == null)
currentForwardType = "all";
// frame: edit|search
String frame = attrs.getValue("", "frame");
if (frame == null)
frame = "";
String nextActionRef = attrs.getValue("", "nextAction"); // null allowed
String nextActionTempl = null;
// retrieve the action belonging to this name and
// use the action name as the nextActionTemplate
if (nextActionRef != null) {
ActionInGroup nextAction = (ActionInGroup) currentActions.get(nextActionRef);
nextActionTempl = nextAction.getName();
}
// paramRule: short cut to class name
String paramRuleStr = attrs.getValue("", "paramRule"); // null allowed
ParamRuleIF paramRule = null;
if (paramRuleStr!=null && !paramRuleStr.equals("")) {
paramRule = (ParamRuleIF) getClassInstance(paramRuleStr);
}
// finally create instance
currentForwardPage = new ActionForwardPage(getAbsolutePathFor(path), frame, nextActionTempl,
paramRule);
} // ----------------------------------------------------
else if (lname == "reqParam") {
String name = attrs.getValue("", "name");
// value is optional, if not fixed, it will be retrieved
// from request scope.
String value = attrs.getValue("", "value");
currentForwardPage.addParameter(name, value);
} // ----------------------------------------------------
else if (lname == "actionType") {
currentActionType = attrs.getValue("", "class");
} // ----------------------------------------------------
else if (lname == "actionGroup") {
String name = attrs.getValue("", "name");
currentActionGroup = new ActionGroup(name);
currentActions = new HashMap();
currentForwards = new HashMap();
} // ----------------------------------------------------
else if (lname == "inputField" || lname == "action"){
currentActionName = attrs.getValue("", "name");
currentActionClass = attrs.getValue("", "class");
currentActionExclusive = attrs.getValue("", "exclusive");
} // ----------------------------------------------------
else if (lname == "forwardRules") {
currentForwardRules = new HashMap();
} // ----------------------------------------------------
else if (lname == "forwardDefault") {
// first try if attribute 'forward' is set
String defaultForwardName = attrs.getValue("", "forward");
if (defaultForwardName != null) {
ForwardPageResponseComposite fpr = getForward(defaultForwardName);
if (fpr == null)
throw new OntopiaRuntimeException("forwardDefault had undefined forward '" +
defaultForwardName + "' at " +
getPosition());
currentActionGroup.setDefaultForwardPage(fpr.getResponseType(),
fpr.getForwardPage());
} else {
// secondly try to resolve 'path' attribute
String path = attrs.getValue("", "path");
if (path == null) {
String msg = "Either attribute 'path' or 'forward' has to be set (" +
getPosition() + ")";
log.error(msg);
throw new OntopiaRuntimeException(msg);
}
// paramRule: short cut to class name
String paramRuleStr = attrs.getValue("", "paramRule"); // null allowed
ParamRuleIF paramRule = null;
if (paramRuleStr!=null && !paramRuleStr.equals("")) {
paramRule = (ParamRuleIF) getClassInstance(paramRuleStr);
}
ActionForwardPageIF fp = new ActionForwardPage(getAbsolutePathFor(path), paramRule);
currentActionGroup.setDefaultForwardPage(Constants.FORWARD_SUCCESS,
fp);
currentForwardPage = fp;
}
} // ----------------------------------------------------
else if (lname == "forwardLocked") {
// try to resolve 'path' attribute
String path = attrs.getValue("", "path");
if (path == null) {
String msg = "forwardLocked: attribute 'path' has to be specified at " +
getPosition();
log.error(msg);
throw new OntopiaRuntimeException(msg);
}
String frame = attrs.getValue("", "frame");
ActionForwardPageIF fp = new ActionForwardPage(getAbsolutePathFor(path), frame);
currentActionGroup.setLockedForwardPage(fp);
} // ----------------------------------------------------
else if (lname == "forwardRule") {
String forwardName = attrs.getValue("", "forward");
String actionName = attrs.getValue("", "action");
ForwardPageResponseComposite fprc = getForward(forwardName);
if (fprc == null)
throw new OntopiaRuntimeException("forwardRule referenced undefined forward: " + forwardName + " (" + getPosition() + ")");
currentForwardRules.put(getAction(actionName), fprc);
}
super.startElement(nsuri, lname, lname, attrs);
} catch (Exception e) {
e.printStackTrace();
throw new OntopiaRuntimeException(e);
}
}
private String getAbsolutePathFor(String path) {
// If the passed in "path" parameter is a relative URL then
// return it as an absolute URL with respect to the WebApp location.
// If the passed in "path" parameter is already absolute, then
// return it as it is.
if(!path.startsWith("/")) return contextPath + "/" + path;
return path;
}
public void endElement(String nsuri, String lname, String qname) {
try {
super.endElement(nsuri, lname, lname);
// ======================================================
if (lname == "forward") {
int respType = Constants.FORWARD_GENERIC;
if (currentForwardType.equals("success"))
respType = Constants.FORWARD_SUCCESS;
else if (currentForwardType.equals("failure"))
respType = Constants.FORWARD_FAILURE;
// ---
ForwardPageResponseComposite fpr =
new ForwardPageResponseComposite(currentForwardPage, respType);
if (this.isParent("globalForwards")) {
globalForwards.put(currentForwardName, fpr);
} else {
// otherwise it has to be element of actionGroup
currentForwards.put(currentForwardName, fpr);
}
} // ====================================================
else if (lname == "actionGroup") {
registry.addActionGroup(currentActionGroup);
} // ====================================================
else if (lname == "action") {
boolean exclusive = (currentActionExclusive != null &&
currentActionExclusive.trim().equalsIgnoreCase("true"));
ActionIF action = createActionInstance(currentActionClass);
ActionInGroup aig = new ActionInGroup(action, currentActionName, exclusive);
currentActionGroup.addAction(aig);
currentActions.put(currentActionName, aig);
} // ====================================================
else if (lname == "inputField") {
ActionIF action = createActionInstance(currentActionClass);
ActionInGroup aig = new ActionInGroup(action, currentActionName, false);
currentActionGroup.addAction(aig);
} // ====================================================
else if (lname == "forwardRules") {
Iterator it = currentForwardRules.keySet().iterator();
while (it.hasNext()) {
ActionInGroup action = (ActionInGroup) it.next();
ForwardPageResponseComposite fpr =
(ForwardPageResponseComposite) currentForwardRules.get(action);
if (fpr == null)
throw new OntopiaRuntimeException
("No forward page response for forward rule on " + getPosition());
currentActionGroup.setForwardPage(action, fpr.getResponseType(),
fpr.getForwardPage());
}
}
} catch (Exception e) {
e.printStackTrace();
throw new OntopiaRuntimeException(e);
}
}
// ----------------------------------------------------------------
// internal helper methods
// ----------------------------------------------------------------
private String getPosition() {
if (locator == null)
return "<unknown>";
else
return locator.getSystemId() + ":" + locator.getLineNumber() + ":" +
locator.getColumnNumber();
}
private ActionIF createActionInstance(String klassShortcut) {
try {
// try to get the class for the action classname
Class klass = getClass(klassShortcut);
ActionIF action = (ActionIF) actionCache.get(klass);
if (action != null)
return action;
// try to instantiate an object of this action class
action = (ActionIF) klass.newInstance();
actionCache.put(klass, action);
return action;
} catch (Exception e) {
// --- exceptions are of type:
// ClassNotFoundException, NoSuchMethodException, InstantiationException,
// IllegalAccessException, InvocationTargetException
log.error("Cannot create action instance for '" + klassShortcut +
"' (FQCN: " + classMap.get(klassShortcut) + ")", e );
throw new OntopiaRuntimeException("Action object for '" + klassShortcut +
"' cannot be instantiated.", e);
}
}
private ActionInGroup getAction(String actionName) {
ActionInGroup action = (ActionInGroup) currentActions.get(actionName);
if (action == null)
throw new OntopiaRuntimeException("Action " + actionName +" not found.");
return action;
}
private ForwardPageResponseComposite getForward(String forwardName) {
// first try to lookup local forward
ForwardPageResponseComposite forward = (ForwardPageResponseComposite)
currentForwards.get(forwardName);
// if not available, try to lookup global forward
if (forward == null)
forward = (ForwardPageResponseComposite)
globalForwards.get(forwardName);
return forward;
}
private Class getClass(String shortcut) {
String classname = (String) classMap.get(shortcut);
if (classname == null) {
log.error("Class shortname '" + shortcut + "' not declared.");
throw new OntopiaRuntimeException("Class shortname '" + shortcut +
"' not declared.");
}
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
return Class.forName(classname, true, classLoader);
} catch (Exception e) {
log.error("Cannot create instance for class " + classname);
throw new OntopiaRuntimeException("Instantiation of " + classname
+" failed.", e);
}
}
private Object getClassInstance(String shortcut) {
Class klass = getClass(shortcut);
try {
return klass.newInstance();
} catch (Exception e) {
log.error("Cannot instance for class " + classMap.get(shortcut) +
" with empty constructor.");
throw new OntopiaRuntimeException("Instantiation of " + shortcut
+" failed.", e);
}
}
// ----------------------------------------------------------------
// internal helper class
// ----------------------------------------------------------------
class KeyValuePair {
public String key;
public String value;
KeyValuePair(String key, String value) {
this.key = key;
this.value = value;
}
}
}