View Javadoc
1   /**
2    * Copyright 2005-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.web.controller;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.krad.bo.Exporter;
20  import org.kuali.rice.krad.datadictionary.DataDictionary;
21  import org.kuali.rice.krad.datadictionary.DataObjectEntry;
22  import org.kuali.rice.krad.service.DataDictionaryService;
23  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
24  import org.kuali.rice.krad.uif.UifConstants;
25  import org.kuali.rice.krad.uif.UifParameters;
26  import org.kuali.rice.krad.uif.container.CollectionGroup;
27  import org.kuali.rice.krad.uif.layout.collections.TableExporter;
28  import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
29  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
30  import org.kuali.rice.krad.util.GlobalVariables;
31  import org.kuali.rice.krad.util.KRADConstants;
32  import org.kuali.rice.krad.web.form.UifFormBase;
33  import org.springframework.stereotype.Controller;
34  import org.springframework.web.bind.annotation.ModelAttribute;
35  import org.springframework.web.bind.annotation.RequestMapping;
36  import org.springframework.web.bind.annotation.RequestMethod;
37  import org.springframework.web.bind.annotation.ResponseBody;
38  
39  import javax.servlet.http.HttpServletRequest;
40  import javax.servlet.http.HttpServletResponse;
41  import java.util.List;
42  
43  /**
44   * Controller that handles table export requests.
45   *
46   * @author Kuali Rice Team (rice.collab@kuali.org)
47   */
48  @Controller
49  @RequestMapping(value = "/export")
50  public class UifExportController extends UifControllerBase {
51      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(UifExportController.class);
52  
53      /**
54       * Retrieves the session form for the form key request parameter so we can initialize a form instance of the
55       * same type the view was rendered with.
56       *
57       * {@inheritDoc}
58       */
59      @Override
60      protected UifFormBase createInitialForm(HttpServletRequest request) {
61          String formKey = request.getParameter(UifParameters.FORM_KEY);
62          if (StringUtils.isBlank(formKey)) {
63              throw new RuntimeException("Unable to create export form due to misssing form key parameter");
64          }
65  
66          UifFormBase sessionForm = GlobalVariables.getUifFormManager().getSessionForm(formKey);
67          if (sessionForm != null) {
68              try {
69                  return sessionForm.getClass().newInstance();
70              } catch (Exception e) {
71                  throw new RuntimeException("Cannot create export form instance from session form", e);
72              }
73          }
74  
75          return null;
76      }
77  
78      /**
79       * Generates exportable table data as CSV based on the rich table selected.
80       */
81      @MethodAccessible
82      @RequestMapping(method = RequestMethod.GET, params = "methodToCall=" + UifConstants.MethodToCallNames.TABLE_CSV,
83              produces = {"text/csv"})
84      @ResponseBody
85      public String tableCsvRetrieval(@ModelAttribute("KualiForm") UifFormBase form, HttpServletRequest request,
86              HttpServletResponse response) {
87          LOG.debug("processing csv table data request");
88  
89          return retrieveTableData(form, request, response);
90      }
91  
92      /**
93       * Generates exportable table data in xsl based on the rich table selected.
94       */
95      @MethodAccessible
96      @RequestMapping(method = RequestMethod.GET, params = "methodToCall=" + UifConstants.MethodToCallNames.TABLE_XLS,
97              produces = {"application/vnd.ms-excel"})
98      @ResponseBody
99      public String tableXlsRetrieval(@ModelAttribute("KualiForm") UifFormBase form, HttpServletRequest request,
100             HttpServletResponse response) {
101         LOG.debug("processing xls table data request");
102 
103         return retrieveTableData(form, request, response);
104     }
105 
106     /**
107      * Generates exportable table data based on the rich table selected.
108      */
109     @MethodAccessible
110     @RequestMapping(method = RequestMethod.GET, params = "methodToCall=" + UifConstants.MethodToCallNames.TABLE_XML,
111             produces = {"application/xml"})
112     @ResponseBody
113     public String tableXmlRetrieval(@ModelAttribute("KualiForm") UifFormBase form, HttpServletRequest request,
114             HttpServletResponse response) {
115         LOG.debug("processing xml table data request");
116 
117         return retrieveTableData(form, request, response);
118     }
119 
120     /**
121      * Generates exportable table data based on the rich table selected.
122      *
123      * <p>First the lifecycle process is run to rebuild the collection group, then
124      * {@link org.kuali.rice.krad.uif.layout.collections.TableExporter} is invoked to build the export data from
125      * the collection.</p>
126      */
127     protected String retrieveTableData(@ModelAttribute("KualiForm") UifFormBase form, HttpServletRequest request,
128             HttpServletResponse response) {
129         LOG.debug("processing table data request");
130 
131         String formatType = getValidatedFormatType(request.getParameter(UifParameters.FORMAT_TYPE));
132         String contentType = getContentType(formatType);
133 
134         CollectionGroup collectionGroup = (CollectionGroup) ViewLifecycle.performComponentLifecycle(form.getView(),
135                 form, request, response, form.getViewPostMetadata(), form.getUpdateComponentId());
136 
137         // set update none to prevent the lifecycle from being run after the controller finishes
138         form.setAjaxReturnType(UifConstants.AjaxReturnTypes.UPDATENONE.getKey());
139 
140         setAttachmentResponseHeader(response, "export." + formatType, contentType);
141 
142         // check for custom exporter class defined for the data object class
143         DataDictionaryService dictionaryService = KRADServiceLocatorWeb.getDataDictionaryService();
144         DataDictionary dictionary = dictionaryService.getDataDictionary();
145 
146         Class<?> dataObjectClass = collectionGroup.getCollectionObjectClass();
147         DataObjectEntry dataObjectEntry = dictionary.getDataObjectEntry(dataObjectClass.getName());
148 
149         Class<? extends Exporter> exporterClass = null;
150         if (dataObjectEntry != null) {
151             exporterClass = dataObjectEntry.getExporterClass();
152         }
153 
154         if (exporterClass != null) {
155             try {
156                 List<Object> modelCollection = ObjectPropertyUtils.getPropertyValue(form,
157                         collectionGroup.getBindingInfo().getBindingPath());
158 
159                 Exporter exporter = exporterClass.newInstance();
160 
161                 if (exporter.getSupportedFormats(dataObjectClass).contains(formatType)) {
162                     exporter.export(dataObjectEntry.getDataObjectClass(), modelCollection, formatType,
163                             response.getOutputStream());
164 
165                     return null;
166                 }
167             } catch (Exception e) {
168                 throw new RuntimeException("Cannot invoked custom exporter class", e);
169             }
170         }
171 
172         // generic export
173         return TableExporter.buildExportTableData(collectionGroup, form, formatType);
174     }
175 
176     /**
177      * Creates consistent setup of attachment response header.
178      *
179      * @param response http response object
180      * @param filename name of the return file
181      * @param contentType return content type
182      */
183     protected void setAttachmentResponseHeader(HttpServletResponse response, String filename, String contentType) {
184         response.setContentType(contentType);
185         response.setHeader("Content-disposition", "attachment; filename=\"" + filename + "\"");
186         response.setHeader("Expires", "0");
187         response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
188         response.setHeader("Pragma", "public");
189     }
190 
191     /**
192      * Reviews and returns a valid format type, defaults to csv.
193      *
194      * @param formatType format type to validate
195      * @return valid format type
196      */
197     protected String getValidatedFormatType(String formatType) {
198         if (KRADConstants.EXCEL_FORMAT.equals(formatType) || KRADConstants.XML_FORMAT.equals(formatType)) {
199             return formatType;
200         }
201 
202         return KRADConstants.CSV_FORMAT;
203     }
204 
205     /**
206      * Reviews and returns a valid content type, defaults to text/csv.
207      *
208      * @param formatType format type to return content type for
209      * @return valid content type
210      */
211     protected String getContentType(String formatType) {
212         if (KRADConstants.EXCEL_FORMAT.equals(formatType)) {
213             return KRADConstants.EXCEL_MIME_TYPE;
214         } else if (KRADConstants.XML_FORMAT.equals(formatType)) {
215             return KRADConstants.XML_MIME_TYPE;
216         } else {
217             return KRADConstants.CSV_MIME_TYPE;
218         }
219     }
220 }