001: /*
002: * Copyright 2006-2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.opensource.org/licenses/ecl1.php
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.kuali.module.kra.budget.web.struts.action;
017:
018: import java.io.ByteArrayOutputStream;
019: import java.io.IOException;
020: import java.net.URL;
021:
022: import javax.servlet.http.HttpServletRequest;
023: import javax.servlet.http.HttpServletResponse;
024: import javax.xml.parsers.DocumentBuilder;
025: import javax.xml.parsers.DocumentBuilderFactory;
026: import javax.xml.parsers.ParserConfigurationException;
027: import javax.xml.transform.OutputKeys;
028: import javax.xml.transform.Result;
029: import javax.xml.transform.Source;
030: import javax.xml.transform.Transformer;
031: import javax.xml.transform.TransformerFactory;
032: import javax.xml.transform.dom.DOMResult;
033: import javax.xml.transform.dom.DOMSource;
034: import javax.xml.transform.stream.StreamResult;
035: import javax.xml.transform.stream.StreamSource;
036:
037: import org.apache.avalon.framework.logger.Log4JLogger;
038: import org.apache.avalon.framework.logger.Logger;
039: import org.apache.commons.lang.StringUtils;
040: import org.apache.fop.apps.Driver;
041: import org.apache.fop.messaging.MessageHandler;
042: import org.apache.struts.action.ActionForm;
043: import org.apache.struts.action.ActionForward;
044: import org.apache.struts.action.ActionMapping;
045: import org.kuali.core.service.KualiConfigurationService;
046: import org.kuali.core.util.GlobalVariables;
047: import org.kuali.core.util.WebUtils;
048: import org.kuali.kfs.KFSConstants;
049: import org.kuali.kfs.KFSKeyConstants;
050: import org.kuali.kfs.context.SpringContext;
051: import org.kuali.kfs.service.ParameterService;
052: import org.kuali.module.kra.KraConstants;
053: import org.kuali.module.kra.budget.document.BudgetDocument;
054: import org.kuali.module.kra.budget.web.struts.form.BudgetForm;
055: import org.kuali.module.kra.budget.xml.BudgetXml;
056: import org.w3c.dom.Document;
057:
058: /**
059: * This class handles Output Actions for Research Administration.
060: */
061: public class BudgetOutputAction extends BudgetAction {
062:
063: private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
064: .getLogger(BudgetOutputAction.class);
065: private static Logger fopLogger = null; // Needed for fop logging
066:
067: // Parameters used on tag. Only the output page should care about these.
068: private static final String GENERIC_BY_TASK = "genericByTask";
069: private static final String GENERIC_BY_PERIOD = "genericByPeriod";
070: private static final String AGENCY = "agency";
071: private static final String NIH_2590 = "NIH-2590";
072: private static final String NIH_398 = "NIH-398";
073: private static final String NIH_MOD = "NIH-mod";
074: private static final String NIH_SUMMARY = "NSF-summary";
075: private static final String SF_424 = "SF424";
076:
077: /**
078: * Use for generation of PDF that is to be pushed to the browser.
079: *
080: * @param mapping
081: * @param form
082: * @param request
083: * @param response
084: * @return
085: * @throws Exception
086: */
087: public ActionForward pdfOutput(ActionMapping mapping,
088: ActionForm form, HttpServletRequest request,
089: HttpServletResponse response) throws Exception {
090: this .load(mapping, form, request, response); // Make sure BudgetForm is fully populated
091:
092: BudgetForm budgetForm = (BudgetForm) form;
093: BudgetDocument budgetDoc = budgetForm.getBudgetDocument();
094:
095: if (!isOutputPageSelectionValid(budgetForm)) {
096: return mapping.findForward(KFSConstants.MAPPING_BASIC);
097: }
098:
099: Document xmlDocument = makeXml(request, budgetForm, budgetDoc);
100:
101: // Prepare a transformer based on our stylesheet (returned by pickStylesheet).
102: TransformerFactory transformerFactory = TransformerFactory
103: .newInstance();
104: StreamSource streamSource = pickStylesheet(budgetForm
105: .getCurrentOutputReportType(), budgetForm
106: .getCurrentOutputAgencyType(), request);
107: Transformer processor = transformerFactory.newTemplates(
108: streamSource).newTransformer();
109:
110: // XML to XML-FO transformation based on stylesheet just loaded.
111: DOMResult result = new DOMResult();
112: processor.transform(new DOMSource(xmlDocument), result);
113: Document foDocument = (Document) result.getNode();
114:
115: // Set logger for FOP up. org.apache.avalon.framework.logger.Logger is replaced with Jakarta Commons-Logging in FOP 0.92.
116: // See http://xmlgraphics.apache.org/fop/0.20.5/embedding.html#basic-logging for details.
117: if (fopLogger == null) {
118: fopLogger = new Log4JLogger(LOG);
119: MessageHandler.setScreenLogger(fopLogger);
120: }
121:
122: // Create and set up a new fop Driver. Then render the PDF based on the DOM object.
123: Driver driver = new Driver();
124: ByteArrayOutputStream baos = new ByteArrayOutputStream();
125: driver.setLogger(fopLogger);
126: driver.setRenderer(Driver.RENDER_PDF);
127: driver.setOutputStream(baos);
128: driver.render(foDocument);
129:
130: // Retrieve the environment we're in.
131: KualiConfigurationService kualiConfigurationService = SpringContext
132: .getBean(KualiConfigurationService.class);
133: String env = kualiConfigurationService
134: .getPropertyString(KFSConstants.ENVIRONMENT_KEY);
135:
136: WebUtils.saveMimeOutputStreamAsFile(response,
137: "application/pdf", baos, "kraBudget-" + env
138: + budgetDoc.getBudget().getDocumentNumber()
139: + ".pdf");
140:
141: return null; // because saveMimeOutputStreamAsFile commits the response
142: }
143:
144: /**
145: * Used for generation of XML data that is to be pushed to the browser.
146: *
147: * @param mapping
148: * @param form
149: * @param request
150: * @param response
151: * @return
152: * @throws Exception
153: */
154: public ActionForward xmlOutput(ActionMapping mapping,
155: ActionForm form, HttpServletRequest request,
156: HttpServletResponse response) throws Exception {
157: this .load(mapping, form, request, response); // Make sure BudgetForm is fully populated
158:
159: BudgetForm budgetForm = (BudgetForm) form;
160: BudgetDocument budgetDoc = budgetForm.getBudgetDocument();
161:
162: // Validation won't be done because it isn't critical that the xml document has the proper parameters.
163:
164: Document xmlDocument = makeXml(request, budgetForm, budgetDoc);
165:
166: // Create transformer with indentation
167: TransformerFactory transformerFactory = TransformerFactory
168: .newInstance();
169: Transformer transformer = transformerFactory.newTransformer();
170: transformer.setOutputProperty(OutputKeys.INDENT, "yes");
171: transformer.setOutputProperty(
172: "{http://xml.apache.org/xalan}indent-amount", "2");
173:
174: // src = our XML source object, dest = byte stream
175: Source src = new DOMSource(xmlDocument);
176: ByteArrayOutputStream baos = new ByteArrayOutputStream();
177: Result dest = new StreamResult(baos);
178: transformer.transform(src, dest);
179:
180: // Retrieve the environment we're in.
181: KualiConfigurationService kualiConfigurationService = SpringContext
182: .getBean(KualiConfigurationService.class);
183: String env = kualiConfigurationService
184: .getPropertyString(KFSConstants.ENVIRONMENT_KEY);
185:
186: WebUtils.saveMimeOutputStreamAsFile(response, "text/xml", baos,
187: "kraBudget-" + env
188: + budgetDoc.getBudget().getDocumentNumber()
189: + ".xml");
190:
191: return null; // because saveMimeOutputStreamAsFile commits the response
192: }
193:
194: /**
195: * Validation check for the output page.
196: *
197: * @param budgetForm
198: * @return whether output page selections are valid
199: */
200: private boolean isOutputPageSelectionValid(BudgetForm budgetForm) {
201: boolean valid = true;
202: if (budgetForm.getCurrentOutputReportType() == null) {
203: GlobalVariables.getErrorMap().putError(
204: "currentOutputReportType",
205: KFSKeyConstants.ERROR_REQUIRED, "Report Type");
206: valid = false;
207: } else {
208: if ((GENERIC_BY_TASK.equals(budgetForm
209: .getCurrentOutputReportType()) || GENERIC_BY_PERIOD
210: .equals(budgetForm.getCurrentOutputReportType()))
211: && StringUtils.isBlank(budgetForm
212: .getCurrentOutputDetailLevel())) {
213: GlobalVariables.getErrorMap().putError(
214: "currentOutputDetailLevel",
215: KFSKeyConstants.ERROR_REQUIRED, "Detail Level");
216: valid = false;
217: }
218: if (AGENCY.equals(budgetForm.getCurrentOutputReportType())
219: && StringUtils.isBlank(budgetForm
220: .getCurrentOutputAgencyType())) {
221: GlobalVariables.getErrorMap().putError(
222: "currentOutputAgencyType",
223: KFSKeyConstants.ERROR_REQUIRED, "Agency Type");
224: valid = false;
225: } else if (AGENCY.equals(budgetForm
226: .getCurrentOutputReportType())
227: && NIH_2590.equals(budgetForm
228: .getCurrentOutputAgencyType())
229: && StringUtils.isBlank(budgetForm
230: .getCurrentOutputAgencyPeriod())) {
231: GlobalVariables.getErrorMap()
232: .putError("currentOutputAgencyPeriod",
233: KFSKeyConstants.ERROR_REQUIRED,
234: "Agency Period");
235: valid = false;
236: }
237: }
238:
239: return valid;
240: }
241:
242: /**
243: * Helper method for pdfOutput and xmlOutput.
244: *
245: * @param request
246: * @param budgetForm
247: * @param budgetDocument
248: * @return newly created Xml document.
249: * @throws ParserConfigurationException
250: * @throws Exception
251: */
252: private Document makeXml(HttpServletRequest request,
253: BudgetForm budgetForm, BudgetDocument budgetDocument)
254: throws ParserConfigurationException, Exception {
255: String imagesUrl = SpringContext.getBean(
256: KualiConfigurationService.class).getPropertyString(
257: KFSConstants.EXTERNALIZABLE_IMAGES_URL_KEY);
258:
259: String param = "";
260: if (GENERIC_BY_TASK.equals(budgetForm
261: .getCurrentOutputReportType())
262: || GENERIC_BY_PERIOD.equals(budgetForm
263: .getCurrentOutputReportType())) {
264: param = budgetForm.getCurrentOutputDetailLevel();
265: } else if (AGENCY.equals(budgetForm
266: .getCurrentOutputReportType())
267: && NIH_2590.equals(budgetForm
268: .getCurrentOutputAgencyType())) {
269: param = budgetForm.getCurrentOutputAgencyPeriod();
270: }
271:
272: // Set DOM objects for XML generation up
273: DocumentBuilderFactory domFactory = DocumentBuilderFactory
274: .newInstance();
275: DocumentBuilder domBuilder = domFactory.newDocumentBuilder();
276: Document xmlDocument = domBuilder.newDocument();
277: BudgetXml
278: .makeXml(budgetDocument, xmlDocument, imagesUrl, param);
279: return xmlDocument;
280: }
281:
282: /**
283: * Returns a file handle to the parameter passed in for a particular style sheet.
284: *
285: * @param currentOutputReportType stylesheet identifier
286: * @param currentOutputAgencyType stylesheet identifier if currentOutputReportType=AGENCY
287: * @param request
288: * @return StreamSource to appropriate stylesheet
289: * @throws IOException
290: */
291: private StreamSource pickStylesheet(String currentOutputReportType,
292: String currentOutputAgencyType, HttpServletRequest request)
293: throws IOException {
294: String urlString = "";
295:
296: // Base URL
297: ParameterService parameterService = SpringContext
298: .getBean(ParameterService.class);
299: urlString = SpringContext.getBean(
300: KualiConfigurationService.class).getPropertyString(
301: KFSConstants.EXTERNALIZABLE_XML_URL_KEY)
302: + parameterService.getParameterValue(
303: BudgetDocument.class,
304: KraConstants.OUTPUT_PATH_PREFIX);
305:
306: // Add the file name based on selection by user
307: if (GENERIC_BY_TASK.equals(currentOutputReportType)) {
308: urlString += parameterService.getParameterValue(
309: BudgetDocument.class,
310: KraConstants.OUTPUT_GENERIC_BY_TASK_XSL_FILENAME);
311: } else if (GENERIC_BY_PERIOD.equals(currentOutputReportType)) {
312: urlString += parameterService.getParameterValue(
313: BudgetDocument.class,
314: KraConstants.OUTPUT_GENERIC_BY_PERIOD_XSL_FILENAME);
315: } else if (AGENCY.equals(currentOutputReportType)) {
316: if (NIH_2590.equals(currentOutputAgencyType)) {
317: urlString += parameterService.getParameterValue(
318: BudgetDocument.class,
319: KraConstants.OUTPUT_NIH2590_XSL_FILENAME);
320: } else if (NIH_398.equals(currentOutputAgencyType)) {
321: urlString += parameterService.getParameterValue(
322: BudgetDocument.class,
323: KraConstants.OUTPUT_NIH398_XSL_FILENAME);
324: } else if (NIH_MOD.equals(currentOutputAgencyType)) {
325: urlString += parameterService.getParameterValue(
326: BudgetDocument.class,
327: KraConstants.OUTPUT_NIH_MODULAR_XSL_FILENAME);
328: } else if (NIH_SUMMARY.equals(currentOutputAgencyType)) {
329: urlString += parameterService.getParameterValue(
330: BudgetDocument.class,
331: KraConstants.OUTPUT_NSF_SUMMARY_XSL_FILENAME);
332: } else {
333: LOG.error("Report type agency stylesheet not found.");
334: }
335: } else if (SF_424.equals(currentOutputReportType)) {
336: urlString += parameterService.getParameterValue(
337: BudgetDocument.class,
338: KraConstants.OUTPUT_SF424_XSL_FILENAME);
339: } else {
340: LOG.error("Report type stylesheet not found.");
341: }
342:
343: return new StreamSource(new URL(urlString).openConnection()
344: .getInputStream());
345: }
346: }
|