2
* @license Highcharts JS v2.3.3 (2012-11-02)
6
* Author: Gert Vaartjes
8
* License: www.highcharts.com/license
10
package com.highcharts.export.controller;
12
import java.io.ByteArrayOutputStream;
13
import java.io.IOException;
14
import java.util.NoSuchElementException;
15
import java.util.concurrent.TimeoutException;
17
import javax.annotation.Resource;
18
import javax.servlet.ServletException;
19
import javax.servlet.http.HttpServlet;
20
import javax.servlet.http.HttpServletRequest;
21
import javax.servlet.http.HttpServletResponse;
23
import org.apache.commons.io.IOUtils;
24
import org.apache.log4j.Logger;
25
import org.springframework.http.HttpStatus;
26
import org.springframework.stereotype.Controller;
27
import org.springframework.web.bind.annotation.ExceptionHandler;
28
import org.springframework.web.bind.annotation.PathVariable;
29
import org.springframework.web.bind.annotation.RequestMapping;
30
import org.springframework.web.bind.annotation.RequestMethod;
31
import org.springframework.web.bind.annotation.RequestParam;
32
import org.springframework.web.servlet.ModelAndView;
34
import com.highcharts.export.converter.SVGConverter;
35
import com.highcharts.export.converter.SVGConverterException;
36
import com.highcharts.export.pool.PoolException;
37
import com.highcharts.export.util.MimeType;
38
import com.highcharts.export.util.TempDir;
40
import java.nio.file.Path;
41
import java.nio.file.Paths;
42
import java.util.logging.Level;
43
import javax.servlet.http.HttpSession;
44
import org.apache.commons.codec.binary.Base64;
45
import org.apache.commons.io.FileUtils;
46
import org.apache.commons.io.FilenameUtils;
47
import org.apache.commons.lang.RandomStringUtils;
48
import org.springframework.http.HttpEntity;
49
import org.springframework.http.HttpHeaders;
53
public class ExportController extends HttpServlet {
54
private static final long serialVersionUID = 1L;
55
private static final Float MAX_WIDTH = 2000.0F;
56
private static final Float MAX_SCALE = 4.0F;
57
protected static Logger logger = Logger.getLogger("exporter");
59
@Resource(name = "svgConverter")
60
private SVGConverter converter;
62
/* catch all GET requests and redirect those */
63
@RequestMapping(method = RequestMethod.GET)
64
public String getAll(HttpSession session) {
66
String tempFile = (String) session.getAttribute("tempFile");
67
session.removeAttribute("tempFile");
69
if (tempFile != null && !tempFile.isEmpty()) {
70
// redirect to file download
71
return "redirect:" + TempDir.getDownloadLink(tempFile);
73
// redirect to demo page
74
return "redirect:demo";
78
@RequestMapping(value = "/demo", method = RequestMethod.GET)
79
public String demo() {
83
@RequestMapping(method = RequestMethod.POST)
84
public HttpEntity<byte[]> exporter(
85
@RequestParam(value = "svg", required = false) String svg,
86
@RequestParam(value = "type", required = false) String type,
87
@RequestParam(value = "filename", required = false) String filename,
88
@RequestParam(value = "width", required = false) String width,
89
@RequestParam(value = "scale", required = false) String scale,
90
@RequestParam(value = "options", required = false) String options,
91
@RequestParam(value = "constr", required = false) String constructor,
92
@RequestParam(value = "callback", required = false) String callback,
93
@RequestParam(value = "async", required = false, defaultValue = "false") Boolean async,
94
HttpServletRequest request,
95
HttpSession session) throws ServletException, InterruptedException, SVGConverterException, NoSuchElementException, PoolException, TimeoutException, IOException {
97
MimeType mime = getMime(type);
98
String tempFilename = null;
100
boolean isAndroid = request.getHeader("user-agent") != null && request.getHeader("user-agent").contains("Android");
102
if (isAndroid || MimeType.PDF.equals(mime) || async) {
103
tempFilename = createUniqueFileName(mime.name().toLowerCase());
106
String output = processRequest(svg, mime, width, scale, options, constructor, callback, tempFilename);
107
ByteArrayOutputStream stream;
110
String link = TempDir.getDownloadLink(tempFilename);
112
stream = new ByteArrayOutputStream();
113
stream.write(link.getBytes("utf-8"));
115
stream = ouputToStream(output, mime, tempFilename);
118
/* If tempFilename is not null, then we want to save the filename in session, in case of GET is used later on*/
120
session.setAttribute("tempFile", FilenameUtils.getName(tempFilename));
123
filename = getFilename(filename);
125
HttpHeaders headers = new HttpHeaders();
126
headers.add("Content-Type", mime.getType() + "; charset=utf-8");
127
headers.add("Content-Disposition",
128
"attachment; filename=" + filename.replace(" ", "_") + "." + mime.name().toLowerCase());
129
headers.setContentLength(stream.size());
131
return new HttpEntity<byte[]>(stream.toByteArray(), headers);
134
@RequestMapping(value = "/files/{name}.{ext}", method = RequestMethod.GET)
135
public void getFile(@PathVariable("name") String name, @PathVariable("ext") String ext, HttpServletResponse response) throws SVGConverterException, IOException {
136
Path path = Paths.get(TempDir.getOutputDir().toString(), name + "." + ext);
138
ByteArrayOutputStream stream = new ByteArrayOutputStream();
140
stream.write(FileUtils.readFileToByteArray(new File(path.toString())));
141
} catch (IOException ioex) {
142
logger.error("Tried to read file from filesystem: " + ioex.getMessage());
143
throw new SVGConverterException("IOException: cannot find your file to download...");
146
MimeType mime = MimeType.valueOf(ext.toUpperCase());
149
response.setCharacterEncoding("utf-8");
150
response.setContentLength(stream.size());
151
response.setContentType(mime.getType());
152
response.setStatus(HttpStatus.OK.value());
153
IOUtils.write(stream.toByteArray(), response.getOutputStream());
154
response.flushBuffer();
158
@ExceptionHandler(IOException.class)
159
public ModelAndView handleIOException(Exception ex) {
160
ModelAndView modelAndView = new ModelAndView();
161
modelAndView.setViewName("error");
162
modelAndView.addObject("message", ex.getMessage());
166
@ExceptionHandler(TimeoutException.class)
167
public ModelAndView handleTimeoutException(Exception ex) {
168
ModelAndView modelAndView = new ModelAndView();
169
modelAndView.setViewName("error");
173
"Timeout converting SVG, is your file this big, or maybe you have a syntax error in the javascript callback?");
177
@ExceptionHandler(PoolException.class)
178
public ModelAndView handleServerPoolException(Exception ex) {
179
ModelAndView modelAndView = new ModelAndView();
180
modelAndView.setViewName("error");
184
"Sorry, the server is handling too many requests at the moment. Please try again.");
188
@ExceptionHandler(SVGConverterException.class)
189
public ModelAndView handleSVGRasterizeException(Exception ex) {
190
ModelAndView modelAndView = new ModelAndView();
191
modelAndView.setViewName("error");
195
"Something went wrong while converting. " + ex.getMessage());
199
@ExceptionHandler(InterruptedException.class)
200
public ModelAndView handleInterruptedException(Exception ex) {
201
ModelAndView modelAndView = new ModelAndView();
202
modelAndView.setViewName("error");
206
"It took too long time to process the options, no SVG is created. Make sure your javascript is correct");
210
@ExceptionHandler(ServletException.class)
211
public ModelAndView handleServletException(Exception ex) {
212
ModelAndView modelAndView = new ModelAndView();
213
modelAndView.setViewName("error");
214
modelAndView.addObject("message", ex.getMessage());
222
private String processRequest(String svg, MimeType mime, String width, String scale, String options, String constructor, String callback, String filename) throws SVGConverterException, PoolException, NoSuchElementException, TimeoutException, ServletException {
224
Float parsedWidth = widthToFloat(width);
225
Float parsedScale = scaleToFloat(scale);
226
options = sanitize(options);
230
boolean convertSvg = false;
232
if (options != null) {
233
// create a svg file out of the options
235
callback = sanitize(callback);
237
// assume SVG conversion
239
throw new ServletException(
240
"The manadatory svg POST parameter is undefined.");
244
throw new ServletException(
245
"The manadatory svg POST parameter is undefined.");
252
if (convertSvg && mime.equals(MimeType.SVG)) {
253
output = converter.redirectSVG(input, filename);
255
output = converter.convert(input, mime, constructor, callback, parsedWidth, parsedScale, filename);
261
private String getFilename(String name) {
262
name = sanitize(name);
263
return (name != null) ? name : "chart";
266
private static MimeType getMime(String mime) {
267
MimeType type = MimeType.get(mime);
274
private static String sanitize(String parameter) {
275
if (parameter != null && !parameter.trim().isEmpty() && !(parameter.compareToIgnoreCase("undefined") == 0)) {
276
return parameter.trim();
281
private static Float widthToFloat(String width) {
282
width = sanitize(width);
284
Float parsedWidth = Float.valueOf(width);
285
if (parsedWidth.compareTo(MAX_WIDTH) > 0) {
288
if (parsedWidth.compareTo(0.0F) > 0) {
295
private static Float scaleToFloat(String scale) {
296
scale = sanitize(scale);
298
Float parsedScale = Float.valueOf(scale);
299
if (parsedScale.compareTo(MAX_SCALE) > 0) {
301
} else if (parsedScale.compareTo(0.0F) > 0) {
308
public String createUniqueFileName(String extension) {
309
Path path = Paths.get(TempDir.outputDir.toString(), RandomStringUtils.randomAlphanumeric(8) + "." + extension);
310
return path.toString();
313
private ByteArrayOutputStream ouputToStream(String output, MimeType mime, String filename) {
314
ByteArrayOutputStream stream = new ByteArrayOutputStream();
316
// for example with PDF files or async download
317
if (output.equalsIgnoreCase(filename)) {
318
stream.write(FileUtils.readFileToByteArray(new File(filename)));
321
if (filename == null) {
322
if (mime.getExtension().equals("svg")) {
323
stream.write(output.getBytes());
325
//decode the base64 string
326
stream.write(Base64.decodeBase64(output));
329
} catch (IOException ex) {
330
java.util.logging.Logger.getLogger(ExportController.class.getName()).log(Level.SEVERE, null, ex);
b'\\ No newline at end of file'