package com.cfinkel.reports.wrappers; import com.cfinkel.reports.exceptions.BadReportSyntaxException; import com.cfinkel.reports.generatedbeans.OutputElement; import com.cfinkel.reports.generatedbeans.PreparedQueryElement; import com.cfinkel.reports.generatedbeans.QueryElement; import com.cfinkel.reports.util.Util; import com.cfinkel.reports.web.WebContext; import org.apache.log4j.Logger; import org.springframework.dao.DataAccessException; import java.text.ParseException; import java.util.*; /** * $Author: charles $ * $Revision: 8904 $ * $Date: 2006-05-01 18:02:06 -0400 (Mon, 01 May 2006) $ * <p/> * Created by IntelliJ IDEA. * User: charles * Date: Mar 25, 2006 * Time: 6:09:54 PM * To change this template use File | Settings | File Templates. */ public class PreparedQuery extends Query { private static final Logger log = Logger.getLogger(PreparedQuery.class); private PreparedQueryElement queryElement; private List<Input> inputs; public QueryElement getQueryElement() { return queryElement; } public PreparedQuery(PreparedQueryElement preparedQueryElement, Report report) throws BadReportSyntaxException { super(preparedQueryElement, null); populateInputs(preparedQueryElement, report); } public PreparedQuery(PreparedQueryElement preparedQueryElement, Report report, OutputElement outputElement) throws BadReportSyntaxException { super(preparedQueryElement, outputElement); populateInputs(preparedQueryElement, report); } private void populateInputs(PreparedQueryElement preparedQueryElement, Report report) throws BadReportSyntaxException { this.queryElement = preparedQueryElement; inputs = new ArrayList<Input>(); for (String inputName : preparedQueryElement.getInputRef()) { Input input = report.getAllInputs().get(inputName); if (input == null) throw new BadReportSyntaxException("Input name " + inputName + " not found."); inputs.add(input); } } /** * inputs is the map from HttpServletRequest.getParameterMap() * * @param inputs * @return * @throws DataAccessException */ public List getData(Map<Input, Object> inputs) throws DataAccessException, ParseException { Object[] queryParameters = getQueryParameters(inputs); String adjustedQuery = adjustQueryToInputs(inputs); String userName = "unknown user"; WebContext user = WebContext.get(); if (user != null) { userName = Util.getUserName(user.getRequest()); } // log: StringBuilder sb = new StringBuilder(); sb.append("User ").append(userName).append(" generated query: \n").append(adjustedQuery).append("\nwith "); if (queryParameters == null) sb.append("no parameters"); else sb.append("parameters ").append(queryParameters.toString()); log.info(sb); // runs the query: return jdbcTemplate.queryForList(adjustedQuery, queryParameters); } /** * todo: this shouldn't happen * * @param parameters * @return * @throws ParseException */ public String getQueryString(Map<Input, Object> parameters) throws ParseException { throw new ParseException("Not yet implemented", 0); } private String adjustQueryToInputs(Map<Input, Object> inputs) { if (inputs == null) return this.queryElement.getSql(); StringBuilder adjustedQuery = new StringBuilder(); StringTokenizer st = new StringTokenizer(this.queryElement.getSql(), "?"); try { adjustedQuery.append(st.nextToken()); // adjust query for multiple-value inputs: for (Input input : this.inputs) { Object value = inputs.get(input); if ((value instanceof String[]) && ((String[]) value).length > 1) { // add question marks: adjustedQuery.append(Util.join("?", ",", ((String[]) value).length)); } else { // just keep one question mark: adjustedQuery.append("?"); } adjustedQuery.append(st.nextToken()); } } catch (NoSuchElementException e) { // possibly reached last token, just return what we have: return adjustedQuery.toString(); } return adjustedQuery.toString(); } private Object[] getQueryParameters(Map<Input, Object> inputsFromRequest) throws ParseException { if (this.inputs.size() == 0) return null; int numberOfInputs = getNumberOfInputs(inputsFromRequest); Object[] queryParameters = new Object[numberOfInputs]; // create parameter map for query: int i = 0; try { // iterate through input refs of this query: for (Input input : this.inputs) { Object obj = inputsFromRequest.get(input); if (obj instanceof String) { queryParameters[i] = input.format((String) obj); i++; } else { // String[] : String[] values = (String[]) obj; for (String value : values) { queryParameters[i] = input.format(value); i++; } } } } catch (ParseException e) { throw e; } return queryParameters; } private int getNumberOfInputs(Map<Input, Object> inputsFromRequest) { int numberOfInputs = 0; for (Input input : this.inputs) { Object obj = (inputsFromRequest.get(input)); if (obj != null) { if (obj instanceof String) { numberOfInputs++; } else { numberOfInputs += ((String[]) obj).length; } } } return numberOfInputs; } }