]> git.argeo.org Git - gpl/argeo-suite.git/blob - org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/FopServlet.java
Experiment with streaming GeoJSON directly
[gpl/argeo-suite.git] / org.argeo.app.servlet.publish / src / org / argeo / app / servlet / publish / FopServlet.java
1 package org.argeo.app.servlet.publish;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.OutputStream;
6 import java.io.StringReader;
7 import java.io.StringWriter;
8 import java.net.URI;
9 import java.net.URL;
10 import java.net.URLDecoder;
11 import java.nio.charset.StandardCharsets;
12 import java.nio.file.Files;
13 import java.nio.file.Paths;
14 import java.util.Map;
15 import java.util.Objects;
16
17 import javax.servlet.ServletException;
18 import javax.servlet.http.HttpServlet;
19 import javax.servlet.http.HttpServletRequest;
20 import javax.servlet.http.HttpServletResponse;
21 import javax.xml.parsers.DocumentBuilderFactory;
22 import javax.xml.transform.Result;
23 import javax.xml.transform.Source;
24 import javax.xml.transform.Templates;
25 import javax.xml.transform.Transformer;
26 import javax.xml.transform.TransformerConfigurationException;
27 import javax.xml.transform.TransformerException;
28 import javax.xml.transform.TransformerFactory;
29 import javax.xml.transform.URIResolver;
30 import javax.xml.transform.sax.SAXResult;
31 import javax.xml.transform.stream.StreamResult;
32 import javax.xml.transform.stream.StreamSource;
33
34 import org.apache.fop.apps.FOPException;
35 import org.apache.fop.apps.Fop;
36 import org.apache.fop.apps.FopFactory;
37 import org.apache.fop.apps.FopFactoryBuilder;
38 import org.apache.xmlgraphics.io.Resource;
39 import org.apache.xmlgraphics.io.ResourceResolver;
40 import org.argeo.api.acr.Content;
41 import org.argeo.api.acr.ContentRepository;
42 import org.argeo.api.acr.ContentSession;
43 import org.argeo.app.geo.GeoUtils;
44 import org.argeo.app.geo.GpxUtils;
45 import org.argeo.cms.acr.xml.XmlNormalizer;
46 import org.argeo.cms.auth.RemoteAuthUtils;
47 import org.argeo.cms.servlet.ServletHttpRequest;
48 import org.argeo.cms.util.LangUtils;
49 import org.geotools.data.collection.ListFeatureCollection;
50 import org.geotools.data.simple.SimpleFeatureCollection;
51 import org.opengis.feature.simple.SimpleFeature;
52
53 import net.sf.saxon.BasicTransformerFactory;
54
55 /**
56 * A servlet transforming an XML view of the data to either FOP or PDF.
57 */
58 public class FopServlet extends HttpServlet {
59 private static final long serialVersionUID = 6906020513498289335L;
60
61 private final static String PROP_ARGEO_FO_XSL = "argeo.fo.xsl";
62
63 private ContentRepository contentRepository;
64
65 private DocumentBuilderFactory documentBuilderFactory;
66 private TransformerFactory transformerFactory;
67 private Templates foTemplates;
68
69 private URL xslUrl;
70
71 @Override
72 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
73 String servletPath = req.getServletPath();
74 String ext = servletPath.substring(servletPath.lastIndexOf('.'));
75 servletPath = servletPath.substring(1, servletPath.lastIndexOf('.'));
76 servletPath = servletPath.substring(servletPath.indexOf('/'), servletPath.length());
77 String path = URLDecoder.decode(servletPath, StandardCharsets.UTF_8);
78
79 boolean pdf = ".pdf".equals(ext);
80 ContentSession session = RemoteAuthUtils.doAs(() -> contentRepository.get(), new ServletHttpRequest(req));
81 Content content = session.get(path);
82
83 // dev only
84 final boolean DEV = false;
85 if (DEV) {
86 try (InputStream in = xslUrl.openStream()) {
87 Source xslSource = new StreamSource(in);
88 foTemplates = transformerFactory.newTemplates(xslSource);
89 if (foTemplates == null)
90 throw new IllegalStateException("Could not instantiate XSL " + xslUrl);
91 } catch (TransformerConfigurationException | IOException e) {
92 throw new IllegalStateException("Cannot instantiate XSL " + xslUrl, e);
93 }
94
95 Source xmlInput = content.adapt(Source.class);
96 XmlNormalizer.print(xmlInput, 0);
97 }
98
99 Source xmlInput = content.adapt(Source.class);
100 String systemId = req.getRequestURL().toString();
101 xmlInput.setSystemId(systemId);
102
103 URIResolver uriResolver = (href, base) -> {
104 try {
105 URI url = URI.create(href);
106 if (url.getScheme() != null) {
107 if (url.getScheme().equals("file")) {
108 InputStream in = Files.newInputStream(Paths.get(URI.create(url.toString())));
109 return new StreamSource(in);
110 }
111 if (url.getScheme().equals("geo2svg")) {
112 String includePath = path + url.getPath();
113 String geoExt = includePath.substring(includePath.lastIndexOf('.'));
114 Content geoContent = session.get(includePath);
115 if (".gpx".equals(geoExt)) {
116 try (InputStream in = geoContent.open(InputStream.class)) {
117 SimpleFeature field = GpxUtils.parseGpxToPolygon(in);
118 SimpleFeatureCollection features = new ListFeatureCollection(field.getType(), field);
119 try (StringWriter writer = new StringWriter()) {
120 GeoUtils.exportToSvg(features, writer, 100, 100);
121 StreamSource res = new StreamSource(new StringReader(writer.toString()));
122 return res;
123 }
124 }
125 } else {
126 throw new UnsupportedOperationException(geoExt + " is not supported");
127 }
128 }
129 }
130 } catch (IOException e) {
131 throw new RuntimeException("Cannot process " + href);
132 }
133
134 String p = href.startsWith("/") ? href : path + '/' + href;
135 p = URLDecoder.decode(p, StandardCharsets.UTF_8);
136 Content subContent = session.get(p);
137 return subContent.adapt(Source.class);
138 };
139
140 ResourceResolver resourceResolver = new ResourceResolver() {
141
142 @Override
143 public Resource getResource(URI uri) throws IOException {
144 String subPath = uri.getPath();
145 Content subContent = session.get(subPath);
146 InputStream in = subContent.open(InputStream.class);
147 return new Resource(in);
148 }
149
150 @Override
151 public OutputStream getOutputStream(URI uri) throws IOException {
152 return null;
153 }
154 };
155
156 try {
157 if (pdf) {
158 FopFactoryBuilder builder = new FopFactoryBuilder(URI.create(req.getRequestURL().toString()),
159 resourceResolver);
160 FopFactory fopFactory = builder.build();
161 // FopFactory fopFactory = FopFactory.newInstance(URI.create(req.getRequestURL().toString()));
162 resp.setContentType("application/pdf");
163 Fop fop = fopFactory.newFop("application/pdf", resp.getOutputStream());
164 Transformer transformer = foTemplates.newTransformer();
165 transformer.setURIResolver(uriResolver);
166 Result fopResult = new SAXResult(fop.getDefaultHandler());
167 transformer.transform(xmlInput, fopResult);
168
169 } else {
170 Result xmlOutput = new StreamResult(resp.getOutputStream());
171 resp.setContentType("application/xml");
172 Transformer transformer = foTemplates.newTransformer();
173 // transformer = transformerFactory.newTransformer();// identity
174 transformer.setURIResolver(uriResolver);
175 transformer.transform(xmlInput, xmlOutput);
176 }
177 } catch (FOPException | IOException | TransformerException e) {
178 throw new RuntimeException("Cannot process " + path, e);
179 }
180
181 }
182
183 @Override
184 public void init() throws ServletException {
185 // for (Enumeration<String> it = getServletConfig().getInitParameterNames(); it.hasMoreElements();)
186 // System.out.println(it.nextElement());
187 // for (String str : getServletContext().getResourcePaths("/"))
188 // System.out.println(str);
189 }
190
191 public void start(Map<String, Object> properties) {
192 documentBuilderFactory = DocumentBuilderFactory.newInstance();
193 documentBuilderFactory.setXIncludeAware(true);
194 documentBuilderFactory.setNamespaceAware(true);
195
196 transformerFactory = new BasicTransformerFactory();
197 // transformerFactory = TransformerFactory.newDefaultInstance();
198 try {
199 String xslStr = LangUtils.get(properties, PROP_ARGEO_FO_XSL);
200 Objects.requireNonNull(xslStr);
201 xslUrl = new URL(xslStr);
202 try (InputStream in = xslUrl.openStream()) {
203 Source xslSource = new StreamSource(in);
204 foTemplates = transformerFactory.newTemplates(xslSource);
205 if (foTemplates == null)
206 throw new IllegalStateException("Could not instantiate XSL " + xslUrl);
207 }
208
209 } catch (TransformerConfigurationException | IOException e) {
210 throw new IllegalStateException("Cannot instantiate XSL " + xslUrl, e);
211 }
212 }
213
214 public void stop(Map<String, Object> properties) {
215
216 }
217
218 public void setContentRepository(ContentRepository contentRepository) {
219 this.contentRepository = contentRepository;
220 }
221
222 }