/**
* Copyright (c) 2009--2014 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
* version 2 (GPLv2). There is NO WARRANTY for this software, express or
* implied, including the implied warranties of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
* along with this software; if not, see
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* Red Hat trademarks are not licensed under GPLv2. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package com.redhat.rhn.frontend.struts;
import com.redhat.rhn.common.localization.LocalizationService;
import com.redhat.rhn.common.security.PermissionException;
import com.redhat.rhn.domain.errata.Errata;
import com.redhat.rhn.domain.kickstart.KickstartData;
import com.redhat.rhn.domain.kickstart.KickstartFactory;
import com.redhat.rhn.domain.org.Org;
import com.redhat.rhn.domain.org.OrgFactory;
import com.redhat.rhn.domain.role.RoleFactory;
import com.redhat.rhn.domain.server.ManagedServerGroup;
import com.redhat.rhn.domain.server.Server;
import com.redhat.rhn.domain.session.WebSession;
import com.redhat.rhn.domain.token.ActivationKey;
import com.redhat.rhn.domain.token.ActivationKeyFactory;
import com.redhat.rhn.domain.token.TokenFactory;
import com.redhat.rhn.domain.user.User;
import com.redhat.rhn.domain.user.UserFactory;
import com.redhat.rhn.frontend.action.common.BadParameterException;
import com.redhat.rhn.frontend.servlets.PxtSessionDelegate;
import com.redhat.rhn.frontend.servlets.PxtSessionDelegateFactory;
import com.redhat.rhn.manager.errata.ErrataManager;
import com.redhat.rhn.manager.system.ServerGroupManager;
import com.redhat.rhn.manager.system.SystemManager;
import com.redhat.rhn.manager.user.UserManager;
import org.apache.commons.lang.StringUtils;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import javax.servlet.http.HttpServletRequest;
/**
* Utility methods for accessing various objects in the scope
* of a request. The objects are created by looking at request
* parameters for their ID's and then retrieving them from the
* appropriate manager.
*
* @version $Rev$
*/
public class RequestContext {
// Request IDs go here.
public static final String LABEL = "label";
public static final String USER_ID = "uid";
public static final String ORG_ID = "oid";
public static final String ERRATA_ID = "eid";
public static final String SID = "sid";
public static final String SID1 = "sid_1";
public static final String CID = "cid";
public static final String PRID = "prid";
public static final String COBBLER_ID = "cobbler_id";
public static final String FILTER_STRING = "filter_string";
public static final String PREVIOUS_FILTER_STRING = "prev_filter_value";
public static final String LIST_DISPLAY_EXPORT = "lde";
public static final String TOKEN_ID = "tid";
public static final String LIST_SORT = "sort";
public static final String SORT_ORDER = "order";
public static final String SORT_ASC = "asc";
public static final String SORT_DESC = "desc";
public static final String METHOD_ID = "cmid";
public static final String KICKSTART_ID = "ksid";
public static final String KSTREE_ID = "kstid";
public static final String KEY_ID = "key_id";
public static final String FILE_LIST_ID = "file_list_id";
public static final String KICKSTART_SCRIPT_ID = "kssid";
public static final String CONFIG_FILE_ID = "cfid";
public static final String SERVER_GROUP_ID = "sgid";
public static final String NAME = "name";
// Request Attributes go here:
public static final String ACTIVATION_KEY = "activationkey";
public static final String KICKSTART = "ksdata";
public static final String ORG = "org";
public static final String SYSTEM = "system";
public static final String SERVER_GROUP = "systemgroup";
public static final String KICKSTART_SESSION = "ksession";
public static final String REQUESTED_URI = "requestedUri";
public static final String KSTREE = "kstree";
public static final String KICKSTART_STATE_DESC = "statedescription";
public static final String PAGE_LIST = "pageList";
public static final String DISPATCH = "dispatch";
public static final String CONFIRM = "confirm";
public static final String FILTER_KEY = "Go";
public static final String NO_SCRIPT = "noscript";
public static final String MODE = "mode";
public static final String POST = "POST";
/**
* Names of pagination elements (and their corresponding attributes).
* - elementName - pagination control button element name
* - lowerAttributeName - name of the request attribute containing index of the first
* element in the paginated list
*/
public enum Pagination {
FIRST("First Page", "first_lower"),
PREV("Previous Page", "prev_lower"),
NEXT("Next Page", "next_lower"),
LAST("Last Page", "last_lower");
private String elementName;
private String lowerAttributeName;
Pagination(String elementNameIn, String lowerAttributeNameIn) {
this.elementName = elementNameIn;
this.lowerAttributeName = lowerAttributeNameIn;
}
/**
* @return the pagination control button element name
*/
public String getElementName() {
return elementName;
}
/**
* @return the name of the request attribute containing index of the first
* element in the paginated list
*/
public String getLowerAttributeName() {
return lowerAttributeName;
}
}
private final HttpServletRequest request;
private User currentUser;
/**
* Create a new context object that looks up objects
* from the request <code>req0</code>
*
* @param req0 the request from which to look up objects
*/
public RequestContext(HttpServletRequest req0) {
request = req0;
}
/**
* Return the request that is used by the context for
* object lookup
* @return the current request
*/
public HttpServletRequest getRequest() {
return request;
}
/**
* Return the currently LOGged in user that is making the
* request.
*
* @return the currently LOGged in user that is making the
* request.
*/
public User getCurrentUser() {
if (currentUser == null) {
currentUser = getLoggedInUser();
}
return currentUser;
}
/**
* Get the currently LOGged in User from the pxt session.
*
* @return Currently LOGged in User.
*/
private User getLoggedInUser() {
/*
* XMLRPC calls handle authentication on their own. We return null
* because findUserSession is never going to correctly find an XMLRPC
* user's sessions.
*/
if (request.getRequestURI().startsWith("/rhn/rpc/api")) {
return null;
}
PxtSessionDelegateFactory factory = PxtSessionDelegateFactory.getInstance();
PxtSessionDelegate pxtDelegate = factory.newPxtSessionDelegate();
Long uid = pxtDelegate.getWebUserId(request);
return ((uid == null) ? null : UserFactory.lookupById(uid));
}
/**
* Get the user on the request based on the "uid" paramter. Used
* when editing Users other than the LOGged in user.
*
* @return User found.
*/
// TODO Write unit tests for getUserFromUIDParameter()
public User getUserFromUIDParameter() {
Long uid = getParamAsLong(USER_ID);
User user = UserManager.lookupUser(getCurrentUser(), uid);
return user;
}
/**
* Return the erratum with the ID given by the request's
* {@link #ERRATA_ID}parameter
* @return the erratum with the ID given by the request's
* {@link #ERRATA_ID}parameter
* @throws com.redhat.rhn.frontend.action.common.BadParameterException if the request
* does not contain the required parameter, or if the parameter can not be converted
* to a <code>Long</code>
* @throws IllegalArgumentException if no erratum with the ID given in
* the request can be found
*/
public Errata lookupErratum()
throws BadParameterException, IllegalArgumentException {
Long errataId = getRequiredParam(ERRATA_ID);
Errata retval = ErrataManager.lookupErrata(errataId, getCurrentUser());
assertObjectFound(retval, errataId, ERRATA_ID, "erratum");
return retval;
}
/**
* Return the server with the ID given by the request's {@link #SID}
* parameter
* @return the server with the ID given by the request's {@link #SID}
* parameter
* @throws com.redhat.rhn.frontend.action.common.BadParameterException if the request
* does not contain the required parameter, or if the parameter can not be converted
* to a <code>Long</code>
* @throws IllegalArgumentException if no server with the ID given in the
* request can be found
*/
// TODO Write unit tests for lookupServer()
public Server lookupServer()
throws BadParameterException, IllegalArgumentException {
Long serverId = getRequiredParam(SID);
Server retval = SystemManager.lookupByIdAndUser(serverId,
getCurrentUser());
assertObjectFound(retval, serverId, SID, "server");
return retval;
}
/**
* Return the server with the ID given by the request's {@link #SID}
* parameter. Puts the server in the request attributes.
* @return the server with the ID given by the request's {@link #SID}
* parameter
* @throws com.redhat.rhn.frontend.action.common.BadParameterException if the request
* does not contain the required parameter, or if the parameter can not be converted
* to a <code>Long</code>
* @throws IllegalArgumentException if no server with the ID given in the
* request can be found
*/
// TODO Write unit tests for lookupServer()
public Server lookupAndBindServer()
throws BadParameterException, IllegalArgumentException {
if (request.getAttribute(SYSTEM) == null) {
request.setAttribute(SYSTEM, lookupServer());
}
return (Server) request.getAttribute(SYSTEM);
}
/**
* Return the Activation Key with the ID given by the request's {@link #TOKEN_ID}
* parameter. Puts the activation key in the request attributes.
* @return the Activation Key with the ID given by the request's {@link #TOKEN_ID}
* parameter
* @throws com.redhat.rhn.frontend.action.common.BadParameterException if the request
* does not contain the required parameter, or if the parameter can not be converted
* to a <code>Long</code>
* @throws IllegalArgumentException if no Activation Key with the ID given in the
* request can be found
*/
public ActivationKey lookupAndBindActivationKey() {
if (request.getAttribute(ACTIVATION_KEY) == null) {
Long id = getRequiredParam(TOKEN_ID);
ActivationKey key = ActivationKeyFactory.lookupByToken(
TokenFactory.lookup(id,
getCurrentUser().getOrg()));
request.setAttribute(ACTIVATION_KEY, key);
}
return (ActivationKey) request.getAttribute(ACTIVATION_KEY);
}
/**
* Return the Org with the ID given by the request's {@link #TOKEN_ID}
* parameter. Puts the Orgin the request attributes.
* @return the Org with the ID given by the request's {@link #TOKEN_ID}
* parameter
* @throws com.redhat.rhn.frontend.action.common.BadParameterException if the request
* does not contain the required parameter, or if the parameter can not be converted
* to a <code>Long</code>
* @throws IllegalArgumentException if no Org with the ID given in the
* request can be found
*/
public Org lookupAndBindOrg() {
if (request.getAttribute(ORG) == null) {
Long id = getRequiredParam(ORG_ID);
Org org = null;
if (getCurrentUser().hasRole(RoleFactory.SAT_ADMIN)) {
org = OrgFactory.lookupById(id);
}
assertObjectFound(org, id, ORG_ID, "Org");
request.setAttribute(ORG, org);
}
return (Org) request.getAttribute(ORG);
}
/**
* Return the KickstartData with the ID given by the request's {@link #KICKSTART_ID}
* parameter. Puts the activation key in the request attributes.
* @return the KickstartDatay with the ID given by the request's {@link #KICKSTART_ID}
* parameter
* @throws com.redhat.rhn.frontend.action.common.BadParameterException if the request
* does not contain the required parameter, or if the parameter can not be converted
* to a <code>Long</code>
* @throws IllegalArgumentException if no Kickstart Data with the ID given in the
* request can be found
*/
public KickstartData lookupAndBindKickstartData() {
if (request.getAttribute(KICKSTART) == null) {
Long id = getRequiredParam(KICKSTART_ID);
KickstartData data = KickstartFactory.
lookupKickstartDataByIdAndOrg(getCurrentUser().getOrg(),
id);
assertObjectFound(data, id, KICKSTART_ID, "Kickstart Data");
request.setAttribute(KICKSTART, data);
}
return (KickstartData) request.getAttribute(KICKSTART);
}
/**
* Return the ServerGroup with the ID given by the request's {@link #SERVER_GROUP_ID}
* parameter. Puts the ServerGroupin the request attributes.
* @return the ServerGroup with the ID given by the request's {@link #SERVER_GROUP_ID}
* @throws IllegalArgumentException if no ServerGroup with the ID given in the
* request can be found
*/
public ManagedServerGroup lookupAndBindServerGroup() {
if (request.getAttribute(SERVER_GROUP) == null) {
Long id = getRequiredParam(SERVER_GROUP_ID);
ServerGroupManager manager = ServerGroupManager.getInstance();
User user = getCurrentUser();
ManagedServerGroup sg = manager.lookup(id, user);
if (sg == null) {
String msg = "No server group with id = [%s] found.";
throw new IllegalArgumentException(String.format(msg, id));
}
request.setAttribute(SERVER_GROUP, sg);
}
return (ManagedServerGroup) request.getAttribute(SERVER_GROUP);
}
private void assertObjectFound(Object obj, Long id, String paramName, String objName) {
if (obj == null) {
throw new IllegalArgumentException("Could not find " + objName + " with ID " +
paramName + "=" + id);
}
}
/**
* Get the parameter <code>paramName</code> from the request. If
* <code>required</code> is <code>true</code>, this method will never
* return <code>null</code>; instead, it will throw a
* <code>BadParameterException</code> if the parameter is not in the
* request. If <code>required</code> is <code>false</code>, the return
* value can be <code>null</code>.
* @param paramName the name of the parameter
* @param required whether this parameter must be present
* @return the parameter value or null if not required.
*/
// TODO Refactor getParam(String, boolean)
// This method is awkward in that if the required flag is set, an exception may be
// throw. No exception will be thrown though if the flag is not set. Refactor the
// method by removing the boolean argument, and adding a new method,
// getRequiredParam(String) which throws the exception
public String getParam(String paramName, boolean required) {
String param = request.getParameter(paramName);
if (required && param == null) {
throw new BadParameterException("Required parameter [" +
paramName + "] is null");
}
return param;
}
/**
* Get whether a parameter is present in the request.
* @param name The parameter name.
* @return True if the named parameter is in the request.
*/
public boolean hasParam(String name) {
return (request.getParameter(name) != null);
}
/**
* Returns the value of the parameter named param of the request as a Long.
*
* This method will trim the String as well to check for "" and " ". If the
* String is "1234 " it will return a Long with value: 1234. If the String
* is "" and required is true it will treat it like a null value and throw
* BadParameterException.
*
* @param param Name of request parameter to be converted.
*
* @throws BadParameterException if the parameter <code>param</code> can
* not be converted to a Long
*
* @return the value of the parameter named param of the request as a Long.
* <code>null</code> if the parameter is blank.
*/
public Long getParamAsLong(String param) {
String p = request.getParameter(param);
Long result = null;
// Make sure we catch empty strings as well
if (!StringUtils.isBlank(p)) {
try {
result = Long.valueOf(p.trim());
}
catch (NumberFormatException e) {
BadParameterException bad = new BadParameterException(
"The parameter " + param + " must be a Long, but was '" +
p + "'", e);
bad.setStackTrace(e.getStackTrace());
throw bad;
}
}
return result;
}
/**
* Get the parameter <code>paramName</code> from the request and convert
* it to a <code>Long</code>. A BadParameterException is thrown if the
* parameter is not present in the request or can not be converted.
* @param paramName the name of the parameter
* @return the parameter value converted to a <code>Long</code>
*/
public Long getRequiredParam(String paramName) {
Long result = getParamAsLong(paramName);
if (result == null) {
// TODO: One day, BadParameterException will take a message and we
// can do
// throw new BadParameterException("The parameter " + param +
// " is required and must be a Long, but was '" + p +"'");
// That one day has finally arrived! And the coders rejoiced.
throw new BadParameterException("The parameter " + paramName +
" is required, when accessing " + request.getRequestURI());
}
return result;
}
/**
* Get the parameter <code>paramName</code> from the request
* A BadParameterException is thrown if the
* parameter is not present in the request or is empty
* @param paramName the name of the parameter
* @return the parameter value converted to a <code>Long</code>
*/
public String getRequiredParamAsString(String paramName) {
String p = request.getParameter(paramName);
if (StringUtils.isBlank(p)) {
throw new BadParameterException("The parameter " + paramName +
" is required.");
}
return p;
}
/**
* Get the parameter <code>paramName</code> from the request
* A BadParameterException is thrown if the
* parameter is not present in the request or is empty
* @param paramName the name of the parameter
* @return the parameter value converted to a <code>Long</code>
*/
public Long getRequiredParamAsLong(String paramName) {
Long p = getParamAsLong(paramName);
if (p == null) {
throw new BadParameterException("The parameter " + paramName +
" is required.");
}
return p;
}
/**
* If this current Request includes a parameter to indicate the User is attempting
* to produce an export of viewable data then return true.
*
* Only for use with the Old list tag's exporter. The new list tag doesn't use
* "lde" as a parameter, it uses lde_unique(listName).
*
* @return if this request includes an export param
*/
// TODO Write unit tests for isRequestedExport()
public boolean isRequestedExport() {
String lde = request.getParameter(LIST_DISPLAY_EXPORT);
return (lde != null && lde.equals("1"));
}
/**
* Retrieves the currently Logged in user's pxt session. If it doesn't exist, a new
* session is created.
*
* @return The currently Logged in user's pxt session. If it doesn't exist, a new
* session is created.
*/
public WebSession getWebSession() {
PxtSessionDelegateFactory factory = PxtSessionDelegateFactory.getInstance();
PxtSessionDelegate pxtDelegate = factory.newPxtSessionDelegate();
return pxtDelegate.getPxtSession(request);
}
/**
* Get the value for the lowest part of the list to display. This is
* protected so that the setup actions can get this value for redirecting
* the request.
* @return the lowest value to display.
*/
public String processPagination() {
for (Pagination pagination : Pagination.values()) {
if (request.getParameter(pagination.getElementName()) != null) {
return request.getParameter(pagination.getLowerAttributeName());
}
}
return request.getParameter("lower");
}
/**
* Creates a hashmap with pagination vars added.
* @return Returns a new hashmap containing the parameters
*/
// TODO Write unit tests for makeParamMapWithPagination()
public Map<String, Object> makeParamMapWithPagination() {
Map<String, Object> params = new HashMap<String, Object>();
String lower = processPagination();
if (lower != null && lower.length() > 0 && StringUtils.isNumeric(lower)) {
params.put("lower", lower);
}
return params;
}
/**
* Take a HttpServletRequest and build a self-link to the requested page and
* include a name/value parameter. Won't re-append the parameter if adding
* it is re-attempted.
*
* @param name of parameter to add
* @param value value of paramter
* @return url that is built.
*/
public String buildPageLink(String name, String value) {
StringBuilder page = new StringBuilder((String)request
.getAttribute("requestedUri"));
if (request.getQueryString() != null) {
int index = request.getQueryString().indexOf(name + "=");
// if we already have this param in the query string we have to
// reset it to the new value
if (index >= 0) {
Map<String, String> parammap = new TreeMap<String, String>();
String[] params = StringUtils.split(request.getQueryString(),
'&');
// Convert the parameters into a map so we can
// easily replace the value and reformat the query string.
for (String param : params) {
String[] nameval = StringUtils.split(param, '=');
parammap.put(nameval[0], nameval[1]);
}
parammap.remove(name);
parammap.put(name, value);
page.append("?");
Iterator<String> i = parammap.keySet().iterator();
while (i.hasNext()) {
String key = i.next();
page.append(key + "=" + parammap.get(key));
if (i.hasNext()) {
page.append("&");
}
}
}
else {
page.append("?" + name + "=" + value + "&" + request.getQueryString());
return page.toString();
}
}
else {
page.append("?" + name + "=" + value);
}
return page.toString();
}
/**
* Copies an attached parameter to the attributes list
* This is useful when we want to propagate a parameter
* that was passed to us, like sid
* @param paramId the param to copy
*/
public void copyParamToAttributes(String paramId) {
HttpServletRequest req = getRequest();
String param = req.getParameter(paramId);
if (param != null) {
req.setAttribute(paramId, param);
}
}
/**
* Examines a submit action of the name "dispatch"
* with the i18n'ed value of the key passed in.
* This is useful for example in the following
* scenario.. Lets say you have the following html input
* <input type = "submit" name="dispatch"
* value="rhn:localize('copy.to.local')"/>
* Lets suppose 'copy.to.local' was the message key
* you'd pass to localizationService if i18n'ing...
* Lets suppose the en_US value of copy.to.local = Copy To Local
* When the button is submitted, IE will submit
* "dispatch=Copy To Local"
* This means in the submit action we need to i18n
* the button value again when doing a lookup...
* This method is supposed to help there..
* One can just do
* if (requestContext.wasDispatched("copy.to.local"))
* Alternatively one can also extend
* RhnLookupDispatchAction to achieve the same.
* @param messageKey the message key to be i18ned.
* @return true if a "dispatch" parameter
* was set and that equaled the i18ned
* value of the message key
*/
public boolean wasDispatched(String messageKey) {
HttpServletRequest req = getRequest();
if (req.getParameter(DISPATCH) == null) {
return false;
}
String action = req.getParameter(DISPATCH);
LocalizationService ls = LocalizationService.getInstance();
return ls.getMessage(messageKey).equals(action);
}
/**
* Returns if javascript is enabled/not in this page.
* This needs to be used in conjuction with rhn noscript
* taglib.. If you need to use this method add the following line
* to your jsp after the form, so that it gets submitted
* <rhn:noscript/>
* @return true if java script is enabled, false other wise.
*/
public boolean isJavaScriptEnabled() {
return !Boolean.TRUE.toString().equals(getParam(NO_SCRIPT, false));
}
/**
* Simple util to check if the Form on a page was submitted
* This needs to be used in conjuction with rhn submitted
* taglib.. If you need to use this method add the following line
* to your jsp after the form, so that it gets submitted
* <rhn:submitted/>
* @return true if the form was submitted, false other wise
*/
public boolean isSubmitted() {
return Boolean.TRUE.toString().equals(getParam(RhnAction.SUBMITTED, false));
}
/**
* verify that the request is a POST and throw an exception otherwise.
*/
public void requirePost() {
if (!POST.equals(request.getMethod())) {
throw new PermissionException(
LocalizationService.getInstance().getMessage("request.post.check"));
}
}
}