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