]> git.argeo.org Git - gpl/argeo-suite.git/blob - org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/FopServlet.java
Improve build and deployment
[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.api.acr.NamespaceUtils;
44 import org.argeo.app.geo.GeoUtils;
45 import org.argeo.app.geo.GpxUtils;
46 import org.argeo.app.geo.acr.GeoEntityUtils;
47 import org.argeo.cms.acr.xml.XmlNormalizer;
48 import org.argeo.cms.auth.RemoteAuthUtils;
49 import org.argeo.cms.servlet.ServletHttpRequest;
50 import org.argeo.cms.util.LangUtils;
51 import org.locationtech.jts.geom.Geometry;
52 import org.locationtech.jts.geom.Polygon;
53
54 import net.sf.saxon.BasicTransformerFactory;
55
56 /**
57 * A servlet transforming an XML view of the data to either FOP or PDF.
58 */
59 public class FopServlet extends HttpServlet {
60 private static final long serialVersionUID = 6906020513498289335L;
61
62 private final static String PROP_ARGEO_FO_XSL = "argeo.fo.xsl";
63
64 private ContentRepository contentRepository;
65
66 private DocumentBuilderFactory documentBuilderFactory;
67 private TransformerFactory transformerFactory;
68 private Templates foTemplates;
69
70 private URL xslUrl;
71
72 @Override
73 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
74 String servletPath = req.getServletPath();
75 String ext = servletPath.substring(servletPath.lastIndexOf('.'));
76 servletPath = servletPath.substring(1, servletPath.lastIndexOf('.'));
77 servletPath = servletPath.substring(servletPath.indexOf('/'), servletPath.length());
78 String path = URLDecoder.decode(servletPath, StandardCharsets.UTF_8);
79
80 boolean pdf = ".pdf".equals(ext);
81 ContentSession session = RemoteAuthUtils.doAs(() -> contentRepository.get(), new ServletHttpRequest(req));
82 Content content = session.get(path);
83
84 // dev only
85 final boolean DEV = false;
86 if (DEV) {
87 try (InputStream in = xslUrl.openStream()) {
88 Source xslSource = new StreamSource(in);
89 foTemplates = transformerFactory.newTemplates(xslSource);
90 if (foTemplates == null)
91 throw new IllegalStateException("Could not instantiate XSL " + xslUrl);
92 } catch (TransformerConfigurationException | IOException e) {
93 throw new IllegalStateException("Cannot instantiate XSL " + xslUrl, e);
94 }
95
96 Source xmlInput = content.adapt(Source.class);
97 XmlNormalizer.print(xmlInput, 0);
98 }
99
100 Source xmlInput = content.adapt(Source.class);
101 String systemId = req.getRequestURL().toString();
102 xmlInput.setSystemId(systemId);
103
104 URIResolver uriResolver = (href, base) -> {
105 try {
106 URI url = URI.create(href);
107 if (url.getScheme() != null) {
108 if (url.getScheme().equals("file")) {
109 InputStream in = Files.newInputStream(Paths.get(URI.create(url.toString())));
110 return new StreamSource(in);
111 }
112 if (url.getScheme().equals("geo2svg")) {
113 int lastDot = url.getPath().lastIndexOf('.');
114 Polygon polygon;
115 if (lastDot > 0) {
116 String includePath = path + url.getPath();
117 Content geoContent = session.get(includePath);
118 String geoExt = includePath.substring(lastDot);
119 if (".gpx".equals(geoExt)) {
120 try (InputStream in = geoContent.open(InputStream.class)) {
121 polygon = GpxUtils.parseGpxTrackTo(in, Polygon.class);
122 }
123 } else {
124 throw new UnsupportedOperationException(geoExt + " is not supported");
125 }
126 } else {
127 Content geoContent;
128 String attrName;
129 if (url.getPath().startsWith("/@")) {
130 geoContent = content;
131 attrName = url.getPath().substring(2);// remove /@
132 } else {
133 throw new IllegalArgumentException("Only direct attributes are currently supported");
134 }
135 polygon = GeoEntityUtils.getGeometry(geoContent, NamespaceUtils.parsePrefixedName(attrName),
136 Polygon.class);
137 }
138 try (StringWriter writer = new StringWriter()) {
139 GeoUtils.exportToSvg(new Geometry[] { polygon }, writer, 100, 100);
140 StreamSource res = new StreamSource(new StringReader(writer.toString()));
141 return res;
142 }
143 }
144 }
145 } catch (IOException e) {
146 throw new RuntimeException("Cannot process " + href);
147 }
148
149 String p = href.startsWith("/") ? href : path + '/' + href;
150 p = URLDecoder.decode(p, StandardCharsets.UTF_8);
151 Content subContent = session.get(p);
152 return subContent.adapt(Source.class);
153 };
154
155 ResourceResolver resourceResolver = new ResourceResolver() {
156
157 @Override
158 public Resource getResource(URI uri) throws IOException {
159 String subPath = uri.getPath();
160 Content subContent = session.get(subPath);
161 InputStream in = subContent.open(InputStream.class);
162 return new Resource(in);
163 }
164
165 @Override
166 public OutputStream getOutputStream(URI uri) throws IOException {
167 return null;
168 }
169 };
170
171 try {
172 if (pdf) {
173 FopFactoryBuilder builder = new FopFactoryBuilder(URI.create(req.getRequestURL().toString()),
174 resourceResolver);
175 FopFactory fopFactory = builder.build();
176 // FopFactory fopFactory = FopFactory.newInstance(URI.create(req.getRequestURL().toString()));
177 resp.setContentType("application/pdf");
178 Fop fop = fopFactory.newFop("application/pdf", resp.getOutputStream());
179 Transformer transformer = foTemplates.newTransformer();
180 transformer.setURIResolver(uriResolver);
181 Result fopResult = new SAXResult(fop.getDefaultHandler());
182 transformer.transform(xmlInput, fopResult);
183
184 } else {
185 Result xmlOutput = new StreamResult(resp.getOutputStream());
186 resp.setContentType("application/xml");
187 Transformer transformer = foTemplates.newTransformer();
188 // transformer = transformerFactory.newTransformer();// identity
189 transformer.setURIResolver(uriResolver);
190 transformer.transform(xmlInput, xmlOutput);
191 }
192 } catch (FOPException | IOException | TransformerException e) {
193 throw new RuntimeException("Cannot process " + path, e);
194 }
195
196 }
197
198 @Override
199 public void init() throws ServletException {
200 // for (Enumeration<String> it = getServletConfig().getInitParameterNames(); it.hasMoreElements();)
201 // System.out.println(it.nextElement());
202 // for (String str : getServletContext().getResourcePaths("/"))
203 // System.out.println(str);
204 }
205
206 public void start(Map<String, Object> properties) {
207 documentBuilderFactory = DocumentBuilderFactory.newInstance();
208 documentBuilderFactory.setXIncludeAware(true);
209 documentBuilderFactory.setNamespaceAware(true);
210
211 transformerFactory = new BasicTransformerFactory();
212 // transformerFactory = TransformerFactory.newDefaultInstance();
213 try {
214 String xslStr = LangUtils.get(properties, PROP_ARGEO_FO_XSL);
215 Objects.requireNonNull(xslStr);
216 xslUrl = new URL(xslStr);
217 try (InputStream in = xslUrl.openStream()) {
218 Source xslSource = new StreamSource(in);
219 foTemplates = transformerFactory.newTemplates(xslSource);
220 if (foTemplates == null)
221 throw new IllegalStateException("Could not instantiate XSL " + xslUrl);
222 }
223
224 } catch (TransformerConfigurationException | IOException e) {
225 throw new IllegalStateException("Cannot instantiate XSL " + xslUrl, e);
226 }
227 }
228
229 public void stop(Map<String, Object> properties) {
230
231 }
232
233 public void setContentRepository(ContentRepository contentRepository) {
234 this.contentRepository = contentRepository;
235 }
236
237 }