]> git.argeo.org Git - gpl/argeo-suite.git/blob - swt/org.argeo.app.ui/src/org/argeo/app/ui/docbook/DbkTextInterpreter.java
Prepare refactoring suite UX
[gpl/argeo-suite.git] / swt / org.argeo.app.ui / src / org / argeo / app / ui / docbook / DbkTextInterpreter.java
1 package org.argeo.app.ui.docbook;
2
3 import static org.argeo.app.docbook.DbkType.para;
4 import static org.argeo.app.docbook.DbkType.title;
5 import static org.argeo.app.docbook.DbkUtils.isDbk;
6
7 import java.io.ByteArrayInputStream;
8 import java.io.IOException;
9 import java.io.InputStream;
10 import java.io.StringReader;
11 import java.nio.charset.StandardCharsets;
12 import java.util.List;
13
14 import javax.jcr.ImportUUIDBehavior;
15 import javax.jcr.Item;
16 import javax.jcr.Node;
17 import javax.jcr.NodeIterator;
18 import javax.jcr.Property;
19 import javax.jcr.PropertyIterator;
20 import javax.jcr.RepositoryException;
21
22 import org.apache.commons.io.IOUtils;
23 import org.argeo.app.docbook.DbkAttr;
24 import org.argeo.app.docbook.DbkType;
25 import org.argeo.jcr.Jcr;
26 import org.argeo.jcr.JcrException;
27
28 /** Based on HTML with a few Wiki-like shortcuts. */
29 public class DbkTextInterpreter implements TextInterpreter {
30 // private DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
31
32 private String linkCssClass = DbkType.link.name();
33
34 @Override
35 public void write(Item item, String content) {
36 try {
37 if (item instanceof Node) {
38 Node node = (Node) item;
39 if (isDbk(node, para) || isDbk(node, title)) {
40 String raw = convertToStorage(node, content);
41 validateBeforeStoring(raw);
42
43 String jcrUuid = node.getIdentifier();
44 // if (node.hasProperty(Property.JCR_UUID))
45 // jcrUuid = node.getProperty(Property.JCR_UUID).getString();
46 // else {
47 // // TODO use time based
48 // jcrUuid = UUID.randomUUID().toString();
49 // node.setProperty(Property.JCR_UUID, jcrUuid);
50 // node.getSession().save();
51 // }
52
53 StringBuilder namespaces = new StringBuilder();
54 namespaces.append(" xmlns:dbk=\"http://docbook.org/ns/docbook\"");
55 namespaces.append(" xmlns:jcr=\"http://www.jcp.org/jcr/1.0\"");
56 namespaces.append(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"");
57 raw = "<" + node.getName() + " jcr:uuid=\"" + jcrUuid + "\"" + namespaces + ">" + raw + "</"
58 + node.getName() + ">";
59 // System.out.println(raw);
60 try (InputStream in = new ByteArrayInputStream(raw.getBytes(StandardCharsets.UTF_8))) {
61 node.getSession().importXML(node.getParent().getPath(), in,
62 ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
63 // node.getSession().save();
64 } catch (IOException e) {
65 throw new IllegalArgumentException("Cannot parse raw content of " + node, e);
66 }
67
68 // try {
69 // DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
70 // Document document;
71 // try (Reader in = new StringReader(raw)) {
72 // document = documentBuilder.parse(new InputSource(in));
73 // }
74 // NodeList nl = document.getChildNodes();
75 // for (int i = 0; i < nl.getLength(); i++) {
76 // org.w3c.dom.Node n = nl.item(i);
77 // if (node instanceof Text) {
78 //
79 // }
80 // }
81 // } catch (ParserConfigurationException | SAXException | IOException e) {
82 // throw new IllegalArgumentException("Cannot parse raw content of " + node, e);
83 // }
84
85 // Node jcrText;
86 // if (!node.hasNode(Jcr.JCR_XMLTEXT))
87 // jcrText = node.addNode(Jcr.JCR_XMLTEXT, JcrxType.JCRX_XMLTEXT);
88 // else
89 // jcrText = node.getNode(Jcr.JCR_XMLTEXT);
90 // jcrText.setProperty(Jcr.JCR_XMLCHARACTERS, raw);
91 } else {
92 throw new IllegalArgumentException("Don't know how to interpret " + node);
93 }
94 } else {// property
95 Property property = (Property) item;
96 property.setValue(content);
97 }
98 // item.getSession().save();
99 } catch (RepositoryException e) {
100 throw new JcrException("Cannot set content on " + item, e);
101 }
102 }
103
104 @Override
105 public String read(Item item) {
106 try {
107 String raw = raw(item);
108 return convertFromStorage(item, raw);
109 } catch (RepositoryException e) {
110 throw new JcrException("Cannot get " + item + " for edit", e);
111 }
112 }
113
114 @Override
115 public String raw(Item item) {
116 try {
117 item.getSession().refresh(true);
118 if (item instanceof Node) {
119 Node node = (Node) item;
120 if (isDbk(node, para) || isDbk(node, title)) {
121 StringBuilder sb = new StringBuilder();
122 readXml(node, sb);
123 // NodeIterator nit = node.getNodes();
124 // while (nit.hasNext()) {
125 // Node child = nit.nextNode();
126 // if (child.getName().equals(Jcr.JCR_XMLTEXT)) {
127 // Node jcrText = node.getNode(Jcr.JCR_XMLTEXT);
128 // String txt = jcrText.getProperty(Jcr.JCR_XMLCHARACTERS).getString();
129 // // TODO make it more robust
130 // // txt = txt.replace("\n", "").replace("\t", "");
131 // txt = txt.replace("\t", " ");
132 // sb.append(txt);
133 // } else {
134 // try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
135 // child.getSession().exportDocumentView(child.getPath(), out, true, false);
136 // sb.append(new String(out.toByteArray(), StandardCharsets.UTF_8));
137 // } catch (IOException e) {
138 // throw new IllegalStateException("Cannot export " + child, e);
139 // }
140 // }
141 // }
142 return sb.toString();
143 } else {
144 throw new IllegalArgumentException("Don't know how to interpret " + node);
145 }
146 } else {// property
147 Property property = (Property) item;
148 return property.getString();
149 }
150 } catch (RepositoryException e) {
151 throw new JcrException("Cannot get " + item + " content", e);
152 }
153 }
154
155 private void readXml(Node node, StringBuilder sb) throws RepositoryException {
156 NodeIterator nit = node.getNodes();
157 while (nit.hasNext()) {
158 Node child = nit.nextNode();
159 if (child.getName().equals(Jcr.JCR_XMLTEXT)) {
160 String txt = child.getProperty(Jcr.JCR_XMLCHARACTERS).getString();
161 // TODO make it more robust
162 // txt = txt.replace("\n", "").replace("\t", "");
163 txt = txt.replace("\t", " ");
164 sb.append(txt);
165 } else {
166 sb.append('<').append(child.getName());
167 PropertyIterator pit = child.getProperties();
168 properties: while (pit.hasNext()) {
169 Property p = pit.nextProperty();
170 if (p.getName().startsWith("jcr:"))
171 continue properties;
172 sb.append(' ').append(p.getName()).append("=\"").append(p.getString()).append('\"');
173 }
174 sb.append('>');
175 readXml(child, sb);
176 // try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
177 // child.getSession().exportDocumentView(child.getPath(), out, true, false);
178 // sb.append(new String(out.toByteArray(), StandardCharsets.UTF_8));
179 // } catch (IOException e) {
180 // throw new IllegalStateException("Cannot export " + child, e);
181 // }
182 sb.append("</").append(child.getName()).append('>');
183 }
184 }
185 }
186
187 private void readAsSimpleHtml(Node node, StringBuilder sb) throws RepositoryException {
188 NodeIterator nit = node.getNodes();
189 while (nit.hasNext()) {
190 Node child = nit.nextNode();
191 if (child.getName().equals(Jcr.JCR_XMLTEXT)) {
192 String txt = child.getProperty(Jcr.JCR_XMLCHARACTERS).getString();
193 // TODO make it more robust
194 // txt = txt.replace("\n", "").replace("\t", "");
195 txt = txt.replace("\t", " ");
196 String html = textToSimpleHtml(txt);
197 sb.append(html);
198 } else if (child.getName().equals(DbkType.link.get())) {
199 if (child.hasProperty(DbkAttr.XLINK_HREF)) {
200 String href = child.getProperty(DbkAttr.XLINK_HREF).getString();
201 // TODO deal with other forbidden XML characters?
202 href = href.replace("&", "&amp;");
203 sb.append("<a class='" + linkCssClass + "' href='").append(href).append("'>");
204 readAsSimpleHtml(child, sb);
205 sb.append("</a>");
206 }
207 } else {
208 // ignore
209 }
210 }
211 }
212
213 private String textToSimpleHtml(String raw) {
214 // FIXME the saved data should be corrected instead.
215 if (raw.indexOf('&') >= 0) {
216 raw = raw.replace("&", "&amp;");
217 }
218 if (raw.indexOf('<') >= 0) {
219 raw = raw.replace("<", "&lt;");
220 }
221 if (raw.indexOf('>') >= 0) {
222 raw = raw.replace(">", "&gt;");
223 }
224 if (raw.indexOf('\"') >= 0) {
225 raw = raw.replace("\"", "&quot;");
226 }
227 if (raw.indexOf('\'') >= 0) {
228 raw = raw.replace("\'", "&apos;");
229 }
230 // raw = "<span style='text-align:justify'>" + raw + "</span>";
231 if (raw.length() == 0)
232 return raw;
233 try (StringReader reader = new StringReader(raw)) {
234 List<String> lines = IOUtils.readLines(reader);
235 if (lines.size() == 1)
236 return lines.get(0);
237 StringBuilder sb = new StringBuilder(raw.length() + lines.size() * BR_LENGTH);
238 for (int i = 0; i < lines.size(); i++) {
239 if (i != 0)
240 sb.append("<br/>");
241 sb.append(lines.get(i));
242 }
243 return sb.toString();
244 }
245 }
246
247 final static int BR_LENGTH = "<br/>".length();
248
249 public String readSimpleHtml(Item item) {
250 try {
251 StringBuilder sb = new StringBuilder();
252 // sb.append("<div style='text-align: justify;'>");
253 readAsSimpleHtml((Node) item, sb);
254 // sb.append("</div>");
255 // System.out.println(sb);
256 return sb.toString();
257 } catch (RepositoryException e) {
258 throw new JcrException("Cannot convert " + item + " to simple HTML", e);
259 }
260 }
261
262 // EXTENSIBILITY
263 /**
264 * To be overridden, in order to make sure that only valid strings are being
265 * stored.
266 */
267 protected void validateBeforeStoring(String raw) {
268 }
269
270 /** To be overridden, in order to support additional formatting. */
271 protected String convertToStorage(Item item, String content) throws RepositoryException {
272 return content;
273
274 }
275
276 /** To be overridden, in order to support additional formatting. */
277 protected String convertFromStorage(Item item, String content) throws RepositoryException {
278 return content;
279 }
280 }