/**
* Copyright (c) 2009--2015 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.audit;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.log4j.Logger;
import org.apache.struts.action.ActionForm;
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 org.stringtree.json.JSONWriter;
import com.redhat.rhn.common.util.DatePicker;
import com.redhat.rhn.frontend.action.common.DateRangePicker;
import com.redhat.rhn.frontend.dto.AuditReviewDto;
import com.redhat.rhn.frontend.struts.RequestContext;
import com.redhat.rhn.frontend.struts.RhnAction;
import com.redhat.rhn.frontend.struts.RhnHelper;
import com.redhat.rhn.frontend.taglibs.list.ListTagHelper;
import com.redhat.rhn.manager.audit.AuditManager;
/**
* AuditSearchAction
* @version $Rev$
*/
public class AuditSearchAction extends RhnAction {
private static Logger log = Logger.getLogger(AuditSearchAction.class);
private Long processStartMilli(DynaActionForm dform,
HttpServletRequest request) {
Calendar yesterday;
Long startMilli = (Long)dform.get("startMilli");
String startDisp;
if (startMilli != null && startMilli >= 0) {
startDisp = (new Date(startMilli)).toString();
}
else {
yesterday = Calendar.getInstance();
yesterday.add(Calendar.DAY_OF_YEAR, -7);
startMilli = yesterday.getTime().getTime();
startDisp = "<<";
}
request.setAttribute("startDisp", startDisp);
request.setAttribute("startMilli", startMilli);
return startMilli;
}
private Long processEndMilli(DynaActionForm dform,
HttpServletRequest request) {
Long endMilli = (Long)dform.get("endMilli");
String endDisp;
if (endMilli != null && endMilli > 0 && endMilli != Long.MAX_VALUE) {
endDisp = (new Date(endMilli)).toString();
}
else {
endMilli = Calendar.getInstance().getTime().getTime();
endDisp = ">>";
}
request.setAttribute("endDisp", endDisp);
request.setAttribute("endMilli", endMilli);
return endMilli;
}
private DateRangePicker.DatePickerResults processTimeArgs(
DynaActionForm dform,
HttpServletRequest request,
Boolean processDates) {
Date start, end;
DateRangePicker drp = new DateRangePicker(dform, request,
new Date(processStartMilli(dform, request)),
new Date(processEndMilli(dform, request)),
DatePicker.YEAR_RANGE_NEGATIVE,
"probedetails.jsp.start_date", "probedetails.jsp.end_date");
DateRangePicker.DatePickerResults dpresults =
drp.processDatePickers(processDates, false);
if (processDates) { // we need to redo {start,end}{Disp,Milli}
start = dpresults.getStart().getDate();
end = dpresults.getEnd().getDate();
request.setAttribute("startDisp", start.toString());
request.setAttribute("startMilli", start.getTime());
request.setAttribute("endDisp", end.toString());
request.setAttribute("endMilli", end.getTime());
}
return dpresults;
}
private List prepareAuditTypes() {
BufferedReader brdr;
LinkedList<String> typelist;
Process proc;
String str = "";
// set up types for checkboxes
try { // cache this, maybe...
proc = Runtime.getRuntime().exec("/sbin/ausearch -m");
brdr = new BufferedReader(
new InputStreamReader(proc.getErrorStream()));
brdr.readLine(); // Argument is required for -m
str = brdr.readLine(); // Valid message types are: ...
str = str.substring(str.indexOf(':') + 2);
brdr.close();
}
catch (IOException ioex) {
log.warn("failed to get ausearch types", ioex);
}
typelist = new LinkedList<String>();
for (String type : str.split(" ")) {
if (!type.equals("ALL")) {
typelist.add(type);
}
}
Collections.sort(typelist);
return typelist;
}
/** {@inheritDoc} */
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
ActionMessages amsgs;
AuditReviewDto aureview;
Boolean parseDates, submitted, unrev;
DateRangePicker.DatePickerResults dpresults;
DynaActionForm dform = (DynaActionForm)form;
HttpSession session = request.getSession(true);
JSONWriter jsonwr = new JSONWriter();
List result = null;
Long start, end, seqno, cacheSeqno;
Map<String, String[]> typemap;
RequestContext requestContext = new RequestContext(request);
String machine;
String[] autypes;
request.setAttribute(ListTagHelper.PARENT_URL, request.getRequestURI());
request.setAttribute("user", requestContext.getCurrentUser());
// what audit types are we looking at?
autypes = dform.getStrings("autypes");
// what machine are we looking at?
machine = dform.getString("machine");
// should we look at the DatePickers?
parseDates = (Boolean)dform.get("parseDates") != null;
// did we receive a form with some checkboxes checked?
submitted = (autypes != null && autypes.length > 0);
// can we mark this section reviewed?
unrev = (Boolean)dform.get("unreviewable") != null;
// get the "page creation time" to determine cache usage
seqno = (Long)dform.get("seqno");
if (seqno == null) {
log.debug("(re-)initializing cache");
session.removeAttribute("auditCacheSeqno");
session.removeAttribute("auditResultCache");
}
// handle search times & make displayable versions
dpresults = processTimeArgs(dform, request, parseDates);
if (parseDates || unrev) {
// if we have to process the DatePickers, it means that the user
// entered a time, which means it's probably not a reviewable
// section
unrev = true;
request.setAttribute("unreviewable", "true");
}
else if (!submitted && request.getAttribute("machine") != null) {
log.debug("auto-submit!");
// this is a click-through from the review list.
// we skip the search dialog and return the default selection
submitted = true;
typemap = AuditManager.getAuditTypeMap();
autypes = typemap.get(RhnHelper.DEFAULT_FORWARD);
}
amsgs = new ActionMessages();
amsgs.add(dpresults.getErrors()); // possibly empty
// search?
if (submitted && dpresults.getErrors().isEmpty()) {
start = dpresults.getStart().getDate().getTime();
end = dpresults.getEnd().getDate().getTime();
cacheSeqno = (Long)session.getAttribute("auditCacheSeqno");
// if the cached seqno is greater or equal to the seqno the browser
// sent, we've seen it before; do a new search
if (cacheSeqno == null || seqno == null ||
cacheSeqno.compareTo(seqno) >= 0) {
log.debug("actual search");
result = AuditManager.getAuditLogs(autypes, machine, start, end);
session.setAttribute("auditCacheSeqno", (new Date()).getTime());
session.setAttribute("auditResultCache", result);
}
else {
log.debug("using cached result");
// may be null (indicates the cached result was null)
result = (List)session.getAttribute("auditResultCache");
}
if (result == null) {
if (!unrev) {
// we need to be able to mark reviewable sections as
// 'reviewed' even if they're empty
result = new LinkedList();
}
else {
amsgs.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage("No results found!", false));
}
}
// check to see if this section has been reviewed
try {
aureview = AuditManager.getReviewInfo(machine, start, end);
// the below may return null, indicating "not reviewed"
request.setAttribute("reviewedBy", aureview.getReviewedBy());
request.setAttribute("reviewedOn", aureview.getReviewedOn());
}
catch (IOException ioex) {
// do nothing
}
request.setAttribute("autypes", autypes);
request.setAttribute("machine", machine);
request.setAttribute("result", result);
}
// set the page creation time
// + 1 so that it's greater than the auditCacheSeqno above
request.setAttribute("seqno", (new Date()).getTime() + 1);
// add any accumulated messages to be displayed
addMessages(request, amsgs);
// either the search had no results, so we go back to the search form,
// or this is what they asked for
if (result == null) {
typemap = AuditManager.getAuditTypeMap();
request.setAttribute("auJsonTypes", jsonwr.write(typemap));
request.setAttribute("machines", AuditManager.getMachines());
request.setAttribute("types", prepareAuditTypes());
// if we processed the DatePickers, reset the "display" times
// so that the DatePickers are displayed again
if (parseDates) {
request.setAttribute("startDisp", "<<");
request.setAttribute("endDisp", ">>");
}
return mapping.findForward(RhnHelper.DEFAULT_FORWARD);
}
return mapping.findForward("view");
}
}