1 package org
.argeo
.app
.ui
.docbook
;
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
;
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
;
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 import javax
.xml
.parsers
.DocumentBuilderFactory
;
23 import org
.apache
.commons
.io
.IOUtils
;
24 import org
.argeo
.app
.docbook
.DbkAttr
;
25 import org
.argeo
.app
.docbook
.DbkType
;
26 import org
.argeo
.jcr
.Jcr
;
27 import org
.argeo
.jcr
.JcrException
;
29 /** Based on HTML with a few Wiki-like shortcuts. */
30 public class DbkTextInterpreter
implements TextInterpreter
{
31 private DocumentBuilderFactory documentBuilderFactory
= DocumentBuilderFactory
.newInstance();
33 private String linkCssClass
= DbkType
.link
.name();
36 public void write(Item item
, String content
) {
38 if (item
instanceof Node
) {
39 Node node
= (Node
) item
;
40 if (isDbk(node
, para
) || isDbk(node
, title
)) {
41 String raw
= convertToStorage(node
, content
);
42 validateBeforeStoring(raw
);
44 String jcrUuid
= node
.getIdentifier();
45 // if (node.hasProperty(Property.JCR_UUID))
46 // jcrUuid = node.getProperty(Property.JCR_UUID).getString();
48 // // TODO use time based
49 // jcrUuid = UUID.randomUUID().toString();
50 // node.setProperty(Property.JCR_UUID, jcrUuid);
51 // node.getSession().save();
54 StringBuilder namespaces
= new StringBuilder();
55 namespaces
.append(" xmlns:dbk=\"http://docbook.org/ns/docbook\"");
56 namespaces
.append(" xmlns:jcr=\"http://www.jcp.org/jcr/1.0\"");
57 namespaces
.append(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"");
58 raw
= "<" + node
.getName() + " jcr:uuid=\"" + jcrUuid
+ "\"" + namespaces
+ ">" + raw
+ "</"
59 + node
.getName() + ">";
60 // System.out.println(raw);
61 try (InputStream in
= new ByteArrayInputStream(raw
.getBytes(StandardCharsets
.UTF_8
))) {
62 node
.getSession().importXML(node
.getParent().getPath(), in
,
63 ImportUUIDBehavior
.IMPORT_UUID_COLLISION_REPLACE_EXISTING
);
64 // node.getSession().save();
65 } catch (IOException e
) {
66 throw new IllegalArgumentException("Cannot parse raw content of " + node
, e
);
70 // DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
72 // try (Reader in = new StringReader(raw)) {
73 // document = documentBuilder.parse(new InputSource(in));
75 // NodeList nl = document.getChildNodes();
76 // for (int i = 0; i < nl.getLength(); i++) {
77 // org.w3c.dom.Node n = nl.item(i);
78 // if (node instanceof Text) {
82 // } catch (ParserConfigurationException | SAXException | IOException e) {
83 // throw new IllegalArgumentException("Cannot parse raw content of " + node, e);
87 // if (!node.hasNode(Jcr.JCR_XMLTEXT))
88 // jcrText = node.addNode(Jcr.JCR_XMLTEXT, JcrxType.JCRX_XMLTEXT);
90 // jcrText = node.getNode(Jcr.JCR_XMLTEXT);
91 // jcrText.setProperty(Jcr.JCR_XMLCHARACTERS, raw);
93 throw new IllegalArgumentException("Don't know how to interpret " + node
);
96 Property property
= (Property
) item
;
97 property
.setValue(content
);
99 // item.getSession().save();
100 } catch (RepositoryException e
) {
101 throw new JcrException("Cannot set content on " + item
, e
);
106 public String
read(Item item
) {
108 String raw
= raw(item
);
109 return convertFromStorage(item
, raw
);
110 } catch (RepositoryException e
) {
111 throw new JcrException("Cannot get " + item
+ " for edit", e
);
116 public String
raw(Item item
) {
118 item
.getSession().refresh(true);
119 if (item
instanceof Node
) {
120 Node node
= (Node
) item
;
121 if (isDbk(node
, para
) || isDbk(node
, title
)) {
122 StringBuilder sb
= new StringBuilder();
124 // NodeIterator nit = node.getNodes();
125 // while (nit.hasNext()) {
126 // Node child = nit.nextNode();
127 // if (child.getName().equals(Jcr.JCR_XMLTEXT)) {
128 // Node jcrText = node.getNode(Jcr.JCR_XMLTEXT);
129 // String txt = jcrText.getProperty(Jcr.JCR_XMLCHARACTERS).getString();
130 // // TODO make it more robust
131 // // txt = txt.replace("\n", "").replace("\t", "");
132 // txt = txt.replace("\t", " ");
135 // try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
136 // child.getSession().exportDocumentView(child.getPath(), out, true, false);
137 // sb.append(new String(out.toByteArray(), StandardCharsets.UTF_8));
138 // } catch (IOException e) {
139 // throw new IllegalStateException("Cannot export " + child, e);
143 return sb
.toString();
145 throw new IllegalArgumentException("Don't know how to interpret " + node
);
148 Property property
= (Property
) item
;
149 return property
.getString();
151 } catch (RepositoryException e
) {
152 throw new JcrException("Cannot get " + item
+ " content", e
);
156 private void readXml(Node node
, StringBuilder sb
) throws RepositoryException
{
157 NodeIterator nit
= node
.getNodes();
158 while (nit
.hasNext()) {
159 Node child
= nit
.nextNode();
160 if (child
.getName().equals(Jcr
.JCR_XMLTEXT
)) {
161 String txt
= child
.getProperty(Jcr
.JCR_XMLCHARACTERS
).getString();
162 // TODO make it more robust
163 // txt = txt.replace("\n", "").replace("\t", "");
164 txt
= txt
.replace("\t", " ");
167 sb
.append('<').append(child
.getName());
168 PropertyIterator pit
= child
.getProperties();
169 properties
: while (pit
.hasNext()) {
170 Property p
= pit
.nextProperty();
171 if (p
.getName().startsWith("jcr:"))
173 sb
.append(' ').append(p
.getName()).append("=\"").append(p
.getString()).append('\"');
177 // try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
178 // child.getSession().exportDocumentView(child.getPath(), out, true, false);
179 // sb.append(new String(out.toByteArray(), StandardCharsets.UTF_8));
180 // } catch (IOException e) {
181 // throw new IllegalStateException("Cannot export " + child, e);
183 sb
.append("</").append(child
.getName()).append('>');
188 private void readAsSimpleHtml(Node node
, StringBuilder sb
) throws RepositoryException
{
189 NodeIterator nit
= node
.getNodes();
190 while (nit
.hasNext()) {
191 Node child
= nit
.nextNode();
192 if (child
.getName().equals(Jcr
.JCR_XMLTEXT
)) {
193 String txt
= child
.getProperty(Jcr
.JCR_XMLCHARACTERS
).getString();
194 // TODO make it more robust
195 // txt = txt.replace("\n", "").replace("\t", "");
196 txt
= txt
.replace("\t", " ");
197 String html
= textToSimpleHtml(txt
);
199 } else if (child
.getName().equals(DbkType
.link
.get())) {
200 if (child
.hasProperty(DbkAttr
.XLINK_HREF
)) {
201 String href
= child
.getProperty(DbkAttr
.XLINK_HREF
).getString();
202 // TODO deal with other forbidden XML characters?
203 href
= href
.replace("&", "&");
204 sb
.append("<a class='" + linkCssClass
+ "' href='").append(href
).append("'>");
205 readAsSimpleHtml(child
, sb
);
214 private String
textToSimpleHtml(String raw
) {
215 // FIXME the saved data should be corrected instead.
216 if (raw
.indexOf('&') >= 0) {
217 raw
= raw
.replace("&", "&");
219 if (raw
.indexOf('<') >= 0) {
220 raw
= raw
.replace("<", "<");
222 if (raw
.indexOf('>') >= 0) {
223 raw
= raw
.replace(">", ">");
225 if (raw
.indexOf('\"') >= 0) {
226 raw
= raw
.replace("\"", """);
228 if (raw
.indexOf('\'') >= 0) {
229 raw
= raw
.replace("\'", "'");
231 // raw = "<span style='text-align:justify'>" + raw + "</span>";
232 if (raw
.length() == 0)
234 try (StringReader reader
= new StringReader(raw
)) {
235 List
<String
> lines
= IOUtils
.readLines(reader
);
236 if (lines
.size() == 1)
238 StringBuilder sb
= new StringBuilder(raw
.length() + lines
.size() * BR_LENGTH
);
239 for (int i
= 0; i
< lines
.size(); i
++) {
242 sb
.append(lines
.get(i
));
244 return sb
.toString();
245 } catch (IOException e
) {
246 throw new RuntimeException(e
);
250 final static int BR_LENGTH
= "<br/>".length();
252 public String
readSimpleHtml(Item item
) {
254 StringBuilder sb
= new StringBuilder();
255 // sb.append("<div style='text-align: justify;'>");
256 readAsSimpleHtml((Node
) item
, sb
);
257 // sb.append("</div>");
258 // System.out.println(sb);
259 return sb
.toString();
260 } catch (RepositoryException e
) {
261 throw new JcrException("Cannot convert " + item
+ " to simple HTML", e
);
267 * To be overridden, in order to make sure that only valid strings are being
270 protected void validateBeforeStoring(String raw
) {
273 /** To be overridden, in order to support additional formatting. */
274 protected String
convertToStorage(Item item
, String content
) throws RepositoryException
{
279 /** To be overridden, in order to support additional formatting. */
280 protected String
convertFromStorage(Item item
, String content
) throws RepositoryException
{