/* * EuroCarbDB, a framework for carbohydrate bioinformatics * * Copyright (c) 2006-2009, Eurocarb project, or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * A copy of this license accompanies this distribution in the file LICENSE.txt. * * This program 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. * * Last commit: $Rev: 1987 $ by $Author: glycoslave $ on $Date:: 2010-09-08 #$ */ package org.eurocarbdb.action; // stdlib imports import java.io.ByteArrayOutputStream; import java.net.URI; import java.net.MalformedURLException; import java.util.*; // 3rd party imports import org.apache.log4j.Logger; import com.opensymphony.xwork.Action; import com.opensymphony.xwork.ActionSupport; import com.opensymphony.xwork.ActionContext; import com.opensymphony.xwork.config.entities.ActionConfig; import com.opensymphony.xwork.util.OgnlValueStack; import com.opensymphony.webwork.interceptor.CookiesAware; import com.opensymphony.webwork.interceptor.ParameterAware; import com.opensymphony.webwork.config_browser.ConfigurationHelper; import com.opensymphony.webwork.ServletActionContext; import org.apache.commons.configuration.Configuration; // eurocarb imports import org.eurocarbdb.dataaccess.Eurocarb; import org.eurocarbdb.dataaccess.EurocarbObject; import org.eurocarbdb.dataaccess.core.Contributor; import org.eurocarbdb.dataaccess.core.GlycanSequence; import org.eurocarbdb.util.XmlSerialiser; import org.eurocarbdb.gui.Navigation; // static imports import static org.eurocarbdb.util.StringUtils.join; import static org.eurocarbdb.util.StringUtils.paramToInt; import static org.eurocarbdb.util.StringUtils.lcfirst; import static com.opensymphony.xwork.util.TextParseUtil.translateVariables; /* class EurocarbAction *//**************************************** *<p> * Base class for Eurocarb actions. *</p> *<p> * A note on input parameters: when run in a web context, parameters * passed to an Action class (ie: CGI parameters) may be obtained * in 2 different ways: from the {@link Map} returned by * {@link #getParameters}, or from the inclusion of a <tt>setAbcde</tt> * method in the Action, where <tt>abcde</tt> is the name of a CGI * parameter. <tt>setXxxxx</tt> methods will be called implicitly * by the framework if there is a CGI parameter that matches a * corresponding <tt>set</tt> method and the value of the CGI * parameter can be coerced to the argument type of the set method. *</p> * * @author mjh [glycoslave@gmail.com] */ public abstract class EurocarbAction extends ActionSupport implements EurocarbObject, ParameterAware, CookiesAware { //~~~~~~~~~~~~~~~~~~~~~~ STATIC FIELDS ~~~~~~~~~~~~~~~~~~~~~~~~// protected static final Logger log = Logger.getLogger( EurocarbAction.class ); /** Auto-incrementing counter of instantiated actions, primarily used * to identify which action is which in the logs. */ private static int actionCounter = 0; //~~~~~~~~~~~~~~~~~~~~~~~~~~~ FIELDS ~~~~~~~~~~~~~~~~~~~~~~~~~~// /** Map of all parameters fed to this action, normally populated * by webwork. @see #setParameters */ protected Map<String,String[]> params; /** Identify which submit button in the form has been pressed */ protected String submitAction = ""; /** Specify the list of steps in a workflow */ protected String[] progress_steps = null; /** Specify the current step in a workflow */ protected String current_step = null; /** Cookies map */ protected Map cookiesMap = new HashMap<String,String>(); protected String sugar_image_notation = null; /** Specifies the format to output from this Action. */ private String outputFormat = "html"; public String passErrorMessage=null; /** Assigned at construction time to actionCounter, the index * of this action relative to all other actions run since the * code/server was started. Mainly useful for tracking action * executions in the tomcat logs ;-) */ private final int actionId; protected EurocarbAction() { actionId = ++actionCounter; } //~~~~~~~~~~~~~~~~~~~~~~ STATIC METHODS ~~~~~~~~~~~~~~~~~~~~~~~// //~~~~~~~~~~~~~~~~~~~~~~~~~~ METHODS ~~~~~~~~~~~~~~~~~~~~~~~~// /* getCurrentContributor *//*********************************** * * Returns the currently-active (ie: "logged on", for most * intents and purposes) {@link Contributor}, if any, or the * "guest" Contributor ({@link Contributor.getGuestContributor()}) * if no Contributor is active in the current {@link Thread}. * Note that only one Contributor can be active per {@link Thread} * at any one time (although the application may have many concurrent * users/threads). * * @see Contributor.getGuestContributor() * @see Eurocarb.getCurrentContributor() */ public Contributor getCurrentContributor() { return Contributor.getCurrentContributor(); } /* setParameters *//******************************************* * * Sets a Map of input parameters to be used by this action. * This method is implicitly called when run inside the * webwork/struts framework with any incoming CGI parameters. */ @SuppressWarnings("unchecked") public void setParameters( Map params ) { // suppress-warnings is necessary because the webwork // params hash is pre-java 1.5, and so is not typed. // It does however contain String keys, String[] values // so a direct unchecked cast should be ok. this.params = (Map<String,String[]>) params; if(this.params.containsKey("passErrorMessage")) { passErrorMessage=(this.params.get("passErrorMessage"))[0]; } } /* getParameters *//******************************************* *<p> * Gets the Map of input parameters that have been provided to * this action. The keys of the map are parameter names, the values * are an array of String values for those names. *</p> *<p> * Note that this method of accessing input parameters is * independent of the *</p> */ public Map<String,String[]> getParameters() { return params; } protected String[] parametersWhitelist() { ParameterChecking security = this.getClass().getAnnotation(ParameterChecking.class); if (security != null) { return security.whitelist(); } return null; } protected String[] parametersBlacklist() { ParameterChecking security = this.getClass().getAnnotation(ParameterChecking.class); if (security != null) { return security.blacklist(); } return null; } /** * Use a whitelist/blacklist for this action, to determine which parameters we are going to allow * @see ParameterChecking */ public boolean acceptableParameterName(String paramName) { String[] whitelist = parametersWhitelist(); String[] blacklist = parametersBlacklist(); boolean paramsOk = true; if (whitelist != null) { paramsOk = paramsOk && (Arrays.binarySearch(whitelist,paramName) >= 0); } if (blacklist != null) { paramsOk = paramsOk && (Arrays.binarySearch(blacklist,paramName) < 0); } if (! paramsOk ) { log.info("Denying setting of parameter "+paramName); } return paramsOk; } /* getProjectConfiguration *//************************************ * * Returns global (project-wide) properties. These properties * are derived from a eurocarb.properties file on application * startup. * * @see Eurocarb#getConfiguration() */ //public Configuration getProjectConfiguration() { return Eurocarb.getConfiguration(); } /* getProperty *//********************************************* * * Returns the value for a global (project-wide) property. These properties * are derived from various .properties files on application startup, * and from and user preferences if applicable. * * @see Eurocarb#getConfiguration() */ public Object getProperty( String property_name ) { return Eurocarb.getConfiguration().getProperty( property_name ); } /* getAllActions *//******************************************* * * Returns a Set view of all action names in the current namespace * of the current application. * * @see Eurocarb#getProperties() */ public Set getAllActions() { // this currently gets only those actions in the "" // webwork namespace i believe. this may change in the future. return ConfigurationHelper.getActionNames( "" ); } /* getCurrentActionName *//************************************ * * Returns the name of the currently-running action. * * @see Eurocarb#getProperties() */ public String getCurrentActionName() { return ActionContext.getContext().getName(); } /* getCurrentActionNamespace *//******************************* * * Returns the namespace of the currently-running action. * * @see Eurocarb#getProperties() */ public String getCurrentActionNamespace() { return ActionContext.getContext().getName(); } /** * Returns the current output format for this Action. Returns 'html' * by default, unless the {@link #setOutput} has been called, eg: * <code>my_action.action?output=xml</code>. */ public String getOutput() { return outputFormat; } /** * Sets the current output format for this Action. Common values are: * 'html' (the default), and 'xml'. */ public void setOutput( String output_format ) { log.debug("setting output format = " + output_format ); this.outputFormat = output_format; } /** * Returns true if the current action is capable of producing its results * in XML format for the (default) result code 'success', according to * the current application configuration. * * @see #getOutput * @see #setOutput */ public boolean canGenerateXml() { return canGenerateXml( "success" ); } /** * Returns true if the current action is capable of producing its results * in XML format for the given result code, according to the current * application configuration - basically if there is a result named * <code>"[result_code]-xml"</code>, then this method assumes that this * {@link Action} is capable of generating an XML result. * * @see #getOutput * @see #setOutput */ public boolean canGenerateXml( String result_code ) { String action_name = this.getCurrentActionName(); String namespace = ""; ActionConfig ac = ConfigurationHelper.getActionConfig( namespace, action_name ); if ( ac == null ) return false; return ac.getResults().containsKey( result_code + "-xml"); } /** * This method does not return anything useful at the moment, as * Actions do not have {@link Version}s, per se, yet. */ public String getVersion() { return ""; } //~~~ implementation of EurocarbObject interface methods ~~~// /** * Returns a value equivalent to the index of this Action in * a list of all EurocarbActions instantiated since the code/server * was started; primarily useful for indentifying which action * invocation is which in the logs. */ public int getId() { return actionId; } public <T extends EurocarbObject> Class<T> getIdentifierClass() { return (Class<T>) this.getClass(); } /** * The "type" of an action is always "action". * {@inheritDoc} * @see EurocarbObject.getType() */ public final String getType() { return "action"; } /** Set the value of the parameter used to identify which submit * button in the form has been pressed. * @deprecated actions should manage their own state internally */ @Deprecated public void setSubmitAction(String s) { submitAction = s; } /** * Get the name of the submit button in the form that has been pressed * @deprecated actions should manage their own state internally */ @Deprecated public String getSubmitAction() { return submitAction; } @Deprecated public void setProgress( String s ) { System.out.println("setProgress " + s); if ( s == null ) { progress_steps = null; current_step =null; return; } progress_steps = s.split(","); for( int i=0; i<progress_steps.length; i++ ) { if( progress_steps[i].startsWith("#") ) { progress_steps[i] = progress_steps[i].substring(1); current_step = progress_steps[i]; } } } @Deprecated public String[] getProgressSteps() { return progress_steps; } @Deprecated public String getCurrentStep() { return current_step; } /** Called implicitly by webwork. */ @SuppressWarnings("unchecked") public void setCookiesMap( Map cookies ) { if ( cookies != null ) cookiesMap = cookies; else cookiesMap = new HashMap<String,String>(); if ( log.isDebugEnabled() ) { StringBuilder sb = new StringBuilder("cookies set:\n"); for( Map.Entry e : (Set<Map.Entry>) cookies.entrySet() ) sb.append( "\t" + e.getKey() + " = " + e.getValue() + "\n" ); log.debug( sb.toString() ); } } public String getCookieValue( String name ) { return cookiesMap.get(name).toString(); } public void setSugarImageNotation( String n ) { sugar_image_notation = n; } public String getSugarImageNotation() { return sugar_image_notation; } /** * Use the entity manager to get an entity, parsing the parameter from the * parameters hash, and adding errors to the action when this object is not * present */ public <T extends EurocarbObject> T getObjectFromParams(Class<T> c, Map params) { String paramName = c.getName(); paramName = lcfirst(paramName.substring(paramName.lastIndexOf(".")+1)); paramName = paramName + "." + paramName + "Id"; log.debug("Getting parameter "+paramName); T returnObject = getObjectFromParams(c, params, paramName); if (returnObject == null) { this.addActionError("Must supply a valid ID for this action"); if (params.get(paramName) == null) { this.addFieldError(paramName, "No identifier provided"); } else { this.addActionError("Required identifier "+paramName+" not valid -"+paramToInt(params.get(paramName))+"-"); this.addFieldError(paramName, "Bad identifier provided: -"+ paramToInt(params.get(paramName))+"-"); } } else { log.debug("Retrieved object for param with id of "+((EurocarbObject) returnObject).getId()); } return returnObject; } /** * Use the entity manager to get an entity, parsing the parameter from the * parameters hash */ protected <T> T getObjectFromParams( Class<T> c, Map params, String paramName ) { Object identifier; if ((identifier = params.get(paramName)) != null) { return Eurocarb.getEntityManager().lookup( c , paramToInt(identifier) ); } return null; } } // end class