/**
* 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.action.systems;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.action.DynaActionForm;
import redstone.xmlrpc.XmlRpcException;
import redstone.xmlrpc.XmlRpcFault;
import com.redhat.rhn.common.db.datasource.DataResult;
import com.redhat.rhn.common.localization.LocalizationService;
import com.redhat.rhn.frontend.action.BaseSearchAction;
import com.redhat.rhn.frontend.action.common.BadParameterException;
import com.redhat.rhn.frontend.dto.SystemSearchResult;
import com.redhat.rhn.frontend.struts.RequestContext;
import com.redhat.rhn.frontend.struts.RhnHelper;
import com.redhat.rhn.frontend.struts.StrutsDelegate;
import com.redhat.rhn.frontend.taglibs.list.helper.ListRhnSetHelper;
import com.redhat.rhn.frontend.taglibs.list.helper.Listable;
import com.redhat.rhn.manager.rhnset.RhnSetDecl;
/**
* Action handling the advanced system search page.
*/
public class SystemSearchAction extends BaseSearchAction implements Listable {
public static final String DATA_SET = "searchResults";
public static final String[] OPT_GROUPS_TITLES = {"systemsearch.jsp.details",
"systemsearch.jsp.activity",
"systemsearch.jsp.hardware",
"systemsearch.jsp.devices",
"systemsearch.jsp.dmiinfo",
"systemsearch.jsp.networkinfo",
"systemsearch.jsp.packages",
"systemsearch.jsp.location"};
public static final String[][] OPT_GROUPS = {
/* details */
{ SystemSearchHelper.NAME_AND_DESCRIPTION, SystemSearchHelper.ID,
SystemSearchHelper.CUSTOM_INFO,
SystemSearchHelper.SNAPSHOT_TAG,
SystemSearchHelper.RUNNING_KERNEL,
SystemSearchHelper.UUID },
/* activity group */
{ SystemSearchHelper.CHECKIN, SystemSearchHelper.REGISTERED },
/* hardware group */
{ SystemSearchHelper.CPU_MODEL, SystemSearchHelper.CPU_MHZ_LT,
SystemSearchHelper.CPU_MHZ_GT,
SystemSearchHelper.NUM_CPUS_LT,
SystemSearchHelper.NUM_CPUS_GT,
SystemSearchHelper.RAM_LT, SystemSearchHelper.RAM_GT },
/* device group */
{ SystemSearchHelper.HW_DESCRIPTION, SystemSearchHelper.HW_DRIVER,
SystemSearchHelper.HW_DEVICE_ID,
SystemSearchHelper.HW_VENDOR_ID },
/* dmiinfo */
{ SystemSearchHelper.DMI_SYSTEM, SystemSearchHelper.DMI_BIOS,
SystemSearchHelper.DMI_ASSET },
/* network info */
{ SystemSearchHelper.HOSTNAME, SystemSearchHelper.IP,
SystemSearchHelper.IP6 },
/* packages */
{ SystemSearchHelper.INSTALLED_PACKAGES,
SystemSearchHelper.NEEDED_PACKAGES },
/* location */
{ SystemSearchHelper.LOC_ADDRESS, SystemSearchHelper.LOC_BUILDING,
SystemSearchHelper.LOC_ROOM,
SystemSearchHelper.LOC_RACK } };
public static final List<String> VALID_WHERE_STRINGS =
Arrays.asList(new String[] {WHERE_ALL, WHERE_SSM});
private final Logger log = Logger.getLogger(SystemSearchAction.class);
@Override
protected void insureFormDefaults(HttpServletRequest request, DynaActionForm form) {
String search = form.getString(SEARCH_STR).trim();
String where = form.getString(WHERE_TO_SEARCH);
String viewMode = form.getString(VIEW_MODE);
if (where == null || viewMode == null) {
throw new BadParameterException("An expected form var was null");
}
if ("".equals(viewMode)) { // first time viewing page
viewMode = "systemsearch_name_and_description";
form.set(VIEW_MODE, viewMode);
request.setAttribute(VIEW_MODE, viewMode);
}
if ("".equals(where) || !VALID_WHERE_STRINGS.contains(where)) {
form.set(WHERE_TO_SEARCH, "all");
request.setAttribute(WHERE_TO_SEARCH, "all");
}
Boolean fineGrained = (Boolean)form.get(FINE_GRAINED);
request.setAttribute(FINE_GRAINED, fineGrained == null ? false : fineGrained);
Boolean invert = (Boolean) form.get(INVERT_RESULTS);
if (invert == null) {
invert = Boolean.FALSE;
form.set(INVERT_RESULTS, invert);
}
if (invert) {
request.setAttribute(INVERT_RESULTS, "on");
}
else {
request.setAttribute(INVERT_RESULTS, "off");
}
/* Here we set up a hashmap using the string resources key for the various options
* group as a key into the hash, and the string resources/database mode keys as
* the values of the options that are contained within each opt group. The jsp
* uses this hashmap to setup a dropdown box
*/
boolean matchingViewModeFound = false;
Map<String, List<Map<String, String>>> optGroupsMap =
new HashMap<String, List<Map<String, String>>>();
LocalizationService ls = LocalizationService.getInstance();
for (int j = 0; j < OPT_GROUPS_TITLES.length; ++j) {
List<Map<String, String>> options = new ArrayList<Map<String, String>>();
for (int k = 0; k < OPT_GROUPS[j].length; ++k) {
options.add(createDisplayMap(LocalizationService.getInstance()
.getMessage(OPT_GROUPS[j][k]),
OPT_GROUPS[j][k]));
if (OPT_GROUPS[j][k].equals(viewMode)) {
matchingViewModeFound = true;
}
}
optGroupsMap.put(OPT_GROUPS_TITLES[j], options);
}
if (viewMode != null && !matchingViewModeFound) {
throw new BadParameterException("Bad viewMode passed in from form");
}
request.setAttribute(OPT_GROUPS_MAP, optGroupsMap);
request.setAttribute(OPT_GROUPS_KEYS, optGroupsMap.keySet());
request.setAttribute(SEARCH_STR, search);
request.setAttribute(VIEW_MODE, viewMode);
request.setAttribute(WHERE_TO_SEARCH, where);
}
protected ActionForward doExecute(HttpServletRequest request, ActionMapping mapping,
DynaActionForm form) {
String viewMode = form.getString(VIEW_MODE);
String searchString = form.getString(SEARCH_STR).trim();
ActionErrors errs = new ActionErrors();
if (viewMode.equals(SystemSearchHelper.ID) ||
viewMode.equals(SystemSearchHelper.CPU_MHZ_LT) ||
viewMode.equals(SystemSearchHelper.CPU_MHZ_GT) ||
viewMode.equals(SystemSearchHelper.RAM_LT) ||
viewMode.equals(SystemSearchHelper.RAM_GT) ||
viewMode.equals(SystemSearchHelper.NUM_CPUS_LT) ||
viewMode.equals(SystemSearchHelper.NUM_CPUS_GT) ||
viewMode.equals(SystemSearchHelper.CHECKIN) ||
viewMode.equals(SystemSearchHelper.REGISTERED)) {
String regEx = "(\\d)*";
Pattern pattern = Pattern.compile(regEx);
Matcher matcher = pattern.matcher(searchString);
if (!matcher.matches()) {
errs.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage("systemsearch.errors.numeric"));
}
}
// TODO: Set up combined-form validator
// errs.add(RhnValidationHelper.validateDynaActionForm(this, daForm));
addErrors(request, errs);
ListRhnSetHelper helper = new ListRhnSetHelper(this, request, RhnSetDecl.SYSTEMS);
helper.setWillClearSet(false);
helper.setDataSetName(getDataSetName());
helper.setListName(getListName());
helper.execute();
List results = (List) request.getAttribute(getDataSetName());
log.debug("SystemSearch results.size() = " +
(results != null ? results.size() : "null results"));
if ((results != null) && (results.size() == 1)) {
SystemSearchResult s = (SystemSearchResult) results.get(0);
return StrutsDelegate.getInstance().forwardParam(mapping.findForward("single"),
"sid", s.getId().toString());
}
return mapping.findForward(RhnHelper.DEFAULT_FORWARD);
}
protected DataResult performSearch(RequestContext context) {
HttpServletRequest request = context.getRequest();
String searchString = (String)request.getAttribute(SEARCH_STR);
String viewMode = (String)request.getAttribute(VIEW_MODE);
String whereToSearch = (String)request.getAttribute(WHERE_TO_SEARCH);
Boolean invertResults = StringUtils.defaultString(
(String)request.getAttribute(INVERT_RESULTS)).equals("on");
Boolean isFineGrained = (Boolean)request.getAttribute(FINE_GRAINED);
ActionErrors errs = new ActionErrors();
DataResult dr = null;
try {
dr = SystemSearchHelper.systemSearch(context,
searchString,
viewMode,
invertResults,
whereToSearch, isFineGrained);
}
catch (MalformedURLException e) {
log.error("Caught Exception :" + e, e);
errs.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage("packages.search.connection_error"));
}
catch (XmlRpcFault e) {
log.info("Caught Exception :" + e + ", code [" + e.getErrorCode() + "]", e);
if (e.getErrorCode() == 100) {
log.error("Invalid search query", e);
errs.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage("packages.search.could_not_parse_query",
searchString));
}
else if (e.getErrorCode() == 200) {
log.error("Index files appear to be missing: ", e);
errs.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage("packages.search.index_files_missing",
searchString));
}
else {
errs.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage("packages.search.could_not_execute_query",
searchString));
}
}
catch (XmlRpcException e) {
log.error("Caught Exception :" + e, e);
errs.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage("packages.search.connection_error"));
}
if (dr == null) {
ActionMessages messages = new ActionMessages();
messages.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage("systemsearch_no_matches_found"));
getStrutsDelegate().saveMessages(request, messages);
}
if (!errs.isEmpty()) {
addErrors(request, errs);
}
return dr;
}
/** {@inheritDoc} */
private String getListName() {
return RequestContext.PAGE_LIST;
}
/** {@inheritDoc} */
private String getDataSetName() {
return DATA_SET;
}
/**
* Creates a Map with the keys display and value
* @param display the value for display
* @param value the value for value
* @return Returns the map.
*/
private Map createDisplayMap(String display, String value) {
Map<String, String> selection = new HashMap<String, String>();
selection.put("display", display);
selection.put("value", value);
return selection;
}
/** {@inheritDoc} */
public List getResult(RequestContext context) {
String searchString = (String)context.getRequest().getAttribute(SEARCH_STR);
if (!StringUtils.isBlank(searchString)) {
log.debug("SystemSearchSetupAction.getResult() calling performSearch()");
return performSearch(context);
}
log.debug("SystemSearchSetupAction.getResult() returning Collections.EMPTY_LIST");
return Collections.emptyList();
}
}