Skip to content

Commit e9a610f

Browse files
author
Marco Balestri
committed
[KNOWAGE-4803] Added support for scheduled XLS export
1 parent 8d94ba0 commit e9a610f

File tree

5 files changed

+116
-6
lines changed

5 files changed

+116
-6
lines changed

knowagecockpitengine/src/main/java/it/eng/knowage/engine/cockpit/api/export/excel/ExcelExporter.java

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,22 @@
1818
package it.eng.knowage.engine.cockpit.api.export.excel;
1919

2020
import java.io.ByteArrayOutputStream;
21+
import java.io.FileInputStream;
2122
import java.io.IOException;
23+
import java.net.URI;
24+
import java.nio.file.Files;
25+
import java.nio.file.Path;
26+
import java.nio.file.Paths;
2227
import java.util.ArrayList;
2328
import java.util.Arrays;
2429
import java.util.HashMap;
2530
import java.util.List;
2631
import java.util.Locale;
2732
import java.util.Map;
2833

34+
import javax.ws.rs.core.UriBuilder;
35+
36+
import org.apache.commons.codec.binary.Base64;
2937
import org.apache.log4j.LogMF;
3038
import org.apache.log4j.Logger;
3139
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
@@ -49,7 +57,9 @@
4957
import it.eng.knowage.engine.cockpit.api.export.excel.crosstab.CrosstabXLSXExporter;
5058
import it.eng.qbe.serializer.SerializationException;
5159
import it.eng.spago.error.EMFAbstractError;
60+
import it.eng.spago.error.EMFUserError;
5261
import it.eng.spagobi.analiticalmodel.document.bo.ObjTemplate;
62+
import it.eng.spagobi.commons.SingletonConfig;
5363
import it.eng.spagobi.commons.constants.SpagoBIConstants;
5464
import it.eng.spagobi.commons.dao.DAOFactory;
5565
import it.eng.spagobi.tools.dataset.bo.IDataSet;
@@ -74,14 +84,18 @@ public class ExcelExporter {
7484
private final JSONObject body;
7585
private Locale locale;
7686
private int uniqueId = 0;
87+
private String requestURL = "";
7788

7889
private static final String[] WIDGETS_TO_IGNORE = { "image", "text", "python", "r" };
90+
private static final String SCRIPT_NAME = "cockpit-export-xls.js";
91+
private static final String CONFIG_NAME_FOR_EXPORT_SCRIPT_PATH = "internal.nodejs.chromium.export.path";
7992

8093
// Old implementation with parameterMap
81-
public ExcelExporter(String outputType, String userUniqueIdentifier, Map<String, String[]> parameterMap) {
94+
public ExcelExporter(String outputType, String userUniqueIdentifier, Map<String, String[]> parameterMap, String requestURL) {
8295
this.outputType = outputType;
8396
this.userUniqueIdentifier = userUniqueIdentifier;
8497
this.exportWidget = false;
98+
this.requestURL = requestURL;
8599
this.body = new JSONObject();
86100

87101
Locale locale = getLocale(parameterMap);
@@ -159,6 +173,61 @@ public String getMimeType() {
159173
return mimeType;
160174
}
161175

176+
// used only for scheduled exports
177+
// leverages on an external script that uses chromium to open the cockpit and click on the export button
178+
public byte[] getBinaryData(String documentLabel) throws IOException, InterruptedException, EMFUserError {
179+
180+
final Path outputDir = Files.createTempDirectory("knowage-xls-exporter-");
181+
182+
String encodedUserId = Base64.encodeBase64String(userUniqueIdentifier.getBytes("UTF-8"));
183+
184+
// Script
185+
String cockpitExportScriptPath = SingletonConfig.getInstance().getConfigValue(CONFIG_NAME_FOR_EXPORT_SCRIPT_PATH);
186+
Path exportScriptFullPath = Paths.get(cockpitExportScriptPath, SCRIPT_NAME);
187+
188+
if (!Files.isRegularFile(exportScriptFullPath)) {
189+
String msg = String.format("Cannot find export script at \"%s\": did you set the correct value for %s configuration?", exportScriptFullPath,
190+
CONFIG_NAME_FOR_EXPORT_SCRIPT_PATH);
191+
IllegalStateException ex = new IllegalStateException(msg);
192+
logger.error(msg, ex);
193+
throw ex;
194+
}
195+
196+
URI url = UriBuilder.fromUri(requestURL).replaceQueryParam("outputType_description", "HTML").replaceQueryParam("outputType", "HTML").build();
197+
198+
ProcessBuilder processBuilder = new ProcessBuilder("node", exportScriptFullPath.toString(), encodedUserId, outputDir.toString(), url.toString());
199+
Process exec = processBuilder.start();
200+
exec.waitFor();
201+
// the script creates the resulting xls and saves it to outputFile
202+
Path outputFile = outputDir.resolve(documentLabel + "." + outputType.toLowerCase());
203+
return getByteArrayFromFile(outputFile, outputDir);
204+
}
205+
206+
private byte[] getByteArrayFromFile(Path excelFile, Path outputDir) {
207+
try {
208+
FileInputStream fis = new FileInputStream(excelFile.toString());
209+
ByteArrayOutputStream bos = new ByteArrayOutputStream();
210+
byte[] buf = new byte[1024];
211+
for (int readNum; (readNum = fis.read(buf)) != -1;) {
212+
// Writes len bytes from the specified byte array starting at offset off to this byte array output stream
213+
bos.write(buf, 0, readNum); // no doubt here is 0
214+
}
215+
fis.close();
216+
return bos.toByteArray();
217+
} catch (Exception e) {
218+
logger.error("Cannot serialize excel file", e);
219+
throw new SpagoBIRuntimeException("Cannot serialize excel file", e);
220+
} finally {
221+
try {
222+
if (Files.isRegularFile(excelFile))
223+
Files.delete(excelFile);
224+
Files.delete(outputDir);
225+
} catch (Exception e) {
226+
logger.error("Cannot delete temp file", e);
227+
}
228+
}
229+
}
230+
162231
public byte[] getBinaryData(Integer documentId, String documentLabel, String templateString, String options) throws JSONException, SerializationException {
163232
if (templateString == null) {
164233
ObjTemplate template = null;

knowagecockpitengine/src/main/java/it/eng/knowage/engine/cockpit/api/page/PageResource.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ private void openPageInternal(String pageName) {
161161
String outputType = request.getParameter(OUTPUT_TYPE);
162162
if ("xls".equalsIgnoreCase(outputType) || "xlsx".equalsIgnoreCase(outputType)) {
163163
request.setAttribute("template", getIOManager().getTemplateAsString());
164+
String requestURL = getRequestUrlForExcelExport(request);
165+
request.setAttribute("requestURL", requestURL);
164166
dispatchUrl = "/WEB-INF/jsp/ngCockpitExportExcel.jsp";
165167
response.setContentType(MediaType.APPLICATION_OCTET_STREAM);
166168
} else if ("pdf".equalsIgnoreCase(outputType)) {
@@ -267,6 +269,35 @@ private String getRequestUrlForPdfExport(HttpServletRequest request) throws Unsu
267269
return sb.toString();
268270
}
269271

272+
private String getRequestUrlForExcelExport(HttpServletRequest request) throws UnsupportedEncodingException {
273+
274+
String documentLabel = request.getParameter("DOCUMENT_LABEL");
275+
BIObject biObject = null;
276+
try {
277+
biObject = DAOFactory.getBIObjectDAO().loadBIObjectByLabel(documentLabel);
278+
} catch (EMFUserError e) {
279+
throw new SpagoBIRuntimeException("Error retrieving document with label " + documentLabel, e);
280+
}
281+
Engine eng = biObject.getEngine();
282+
String externalUrl = GeneralUtilities.getExternalEngineUrl(eng);
283+
284+
StringBuilder sb = new StringBuilder(externalUrl);
285+
String sep = "?";
286+
Map<String, String[]> parameterMap = request.getParameterMap();
287+
for (String parameter : parameterMap.keySet()) {
288+
String[] values = parameterMap.get(parameter);
289+
if (values != null && values.length > 0) {
290+
sb.append(sep);
291+
sb.append(URLEncoder.encode(parameter, "UTF-8"));
292+
sb.append("=");
293+
sb.append(URLEncoder.encode(values[0], "UTF-8"));
294+
sep = "&";
295+
}
296+
}
297+
sb.append("&scheduledexport=true");
298+
return sb.toString();
299+
}
300+
270301
public String getServiceHostUrl() {
271302
String serviceURL = SpagoBIUtilities.readJndiResource(SingletonConfig.getInstance().getConfigValue("SPAGOBI.SPAGOBI_SERVICE_JNDI"));
272303
serviceURL = serviceURL.substring(0, serviceURL.lastIndexOf('/'));

knowagecockpitengine/src/main/webapp/WEB-INF/jsp/ngCockpitExportExcel.jsp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
2424

2525
<%@ page contentType="applicaton/octet-stream" %>
2626
<%
27+
2728
String outputType = request.getParameter("outputType");
2829
String userId = request.getParameter("user_id");
2930
Map<String,String[]> parameterMap = request.getParameterMap();
3031
3132
Integer documentId = Integer.valueOf(request.getParameter("document"));
3233
String documentLabel = request.getParameter("DOCUMENT_LABEL");
33-
String template = (String) request.getAttribute("template");
34+
String requestURL = (String) request.getAttribute("requestURL");
3435
35-
ExcelExporter excelExporter = new ExcelExporter(outputType, userId, parameterMap);
36+
ExcelExporter excelExporter = new ExcelExporter(outputType, userId, parameterMap, requestURL);
3637
String mimeType = excelExporter.getMimeType();
3738
if(mimeType != null){
38-
byte[] data = excelExporter.getBinaryData(documentId, documentLabel, template, "");
39+
byte[] data = excelExporter.getBinaryData(documentLabel);
3940
4041
response.setHeader("Content-length", Integer.toString(data.length));
4142
response.setHeader("Content-Type", mimeType);

knowagecockpitengine/src/main/webapp/js/src/angular_1.4/cockpit/directives/cockpit-toolbar/cockpitToolbar.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,17 @@ angular.module('cockpitModule')
3737
}
3838
});
3939

40-
function cockpitToolbarControllerFunction($scope,$timeout,$q,windowCommunicationService,cockpitModule_datasetServices,cockpitModule_widgetServices,cockpitModule_templateServices,cockpitModule_properties,cockpitModule_template,$mdDialog,sbiModule_translate,sbiModule_restServices,sbiModule_messaging,sbiModule_download,sbiModule_user,sbiModule_cockpitDocument,sbiModule_config,cockpitModule_gridsterOptions,$mdPanel,cockpitModule_widgetConfigurator,$mdToast,cockpitModule_generalServices,cockpitModule_widgetSelection,$rootScope){
40+
function cockpitToolbarControllerFunction($scope,$timeout,$q,$location,windowCommunicationService,cockpitModule_datasetServices,cockpitModule_widgetServices,cockpitModule_templateServices,cockpitModule_properties,cockpitModule_template,$mdDialog,sbiModule_translate,sbiModule_restServices,sbiModule_messaging,sbiModule_download,sbiModule_user,sbiModule_cockpitDocument,sbiModule_config,cockpitModule_gridsterOptions,$mdPanel,cockpitModule_widgetConfigurator,$mdToast,cockpitModule_generalServices,cockpitModule_widgetSelection,$rootScope){
4141
$scope.translate = sbiModule_translate;
4242
$scope.cockpitModule_properties=cockpitModule_properties;
4343
$scope.cockpitModule_template=cockpitModule_template;
4444
$scope.cockpitModule_widgetServices=cockpitModule_widgetServices;
4545

46+
if ($location.search()['scheduledexport'])
47+
$scope.isScheduledExcelExport = true;
48+
else
49+
$scope.isScheduledExcelExport = false;
50+
4651
$scope.openGeneralConfigurationDialog=function(){
4752
cockpitModule_generalServices.openGeneralConfiguration();
4853
}

knowagecockpitengine/src/main/webapp/js/src/angular_1.4/cockpit/directives/cockpit-toolbar/templates/cockpitToolbar.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,14 @@
5757
</md-button>
5858
</md-fab-actions>
5959
</md-fab-speed-dial>
60-
60+
6161
<md-button aria-label="data" class="md-fab md-raised md-mini fixedSelectionButton animation shrink-down" ng-click="openSelections()" title = "Selections" ng-if="cockpitModule_template.configuration.showSelectionButton && cockpitModule_properties.HAVE_SELECTIONS_OR_FILTERS==true">
6262
<md-icon md-font-icon="fa fa-check-square-o"></md-icon>
6363
<md-tooltip md-direction="bottom">Selections</md-tooltip>
6464
</md-button>
65+
66+
<!-- This button is used only for scheduled excel export with chromium -->
67+
<md-button id="scheduledExcelExportButton" ng-hide="!isScheduledExcelExport" aria-label="menu" class="md-fab md-warn" ng-click="exportExcel('xlsExport')" ><md-button>
68+
6569
</div>
6670
</div>

0 commit comments

Comments
 (0)