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
.jcr
.docbook
.DbkJcrUtils
.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
;
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
;
28 /** Based on HTML with a few Wiki-like shortcuts. */
29 public class DbkTextInterpreter
implements TextInterpreter
{
30 // private DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
32 private String linkCssClass
= DbkType
.link
.name();
35 public void write(Item item
, String content
) {
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
);
43 String jcrUuid
= node
.getIdentifier();
44 // if (node.hasProperty(Property.JCR_UUID))
45 // jcrUuid = node.getProperty(Property.JCR_UUID).getString();
47 // // TODO use time based
48 // jcrUuid = UUID.randomUUID().toString();
49 // node.setProperty(Property.JCR_UUID, jcrUuid);
50 // node.getSession().save();
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
);
69 // DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
71 // try (Reader in = new StringReader(raw)) {
72 // document = documentBuilder.parse(new InputSource(in));
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) {
81 // } catch (ParserConfigurationException | SAXException | IOException e) {
82 // throw new IllegalArgumentException("Cannot parse raw content of " + node, e);
86 // if (!node.hasNode(Jcr.JCR_XMLTEXT))
87 // jcrText = node.addNode(Jcr.JCR_XMLTEXT, JcrxType.JCRX_XMLTEXT);
89 // jcrText = node.getNode(Jcr.JCR_XMLTEXT);
90 // jcrText.setProperty(Jcr.JCR_XMLCHARACTERS, raw);
92 throw new IllegalArgumentException("Don't know how to interpret " + node
);
95 Property property
= (Property
) item
;
96 property
.setValue(content
);
98 // item.getSession().save();
99 } catch (RepositoryException e
) {
100 throw new JcrException("Cannot set content on " + item
, e
);
105 public String
read(Item item
) {
107 String raw
= raw(item
);
108 return convertFromStorage(item
, raw
);
109 } catch (RepositoryException e
) {
110 throw new JcrException("Cannot get " + item
+ " for edit", e
);
115 public String
raw(Item item
) {
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();
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", " ");
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);
142 return sb
.toString();
144 throw new IllegalArgumentException("Don't know how to interpret " + node
);
147 Property property
= (Property
) item
;
148 return property
.getString();
150 } catch (RepositoryException e
) {
151 throw new JcrException("Cannot get " + item
+ " content", e
);
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", " ");
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:"))
172 sb
.append(' ').append(p
.getName()).append("=\"").append(p
.getString()).append('\"');
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);
182 sb
.append("</").append(child
.getName()).append('>');
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
);
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("&", "&");
203 sb
.append("<a class='" + linkCssClass
+ "' href='").append(href
).append("'>");
204 readAsSimpleHtml(child
, sb
);
213 private String
textToSimpleHtml(String raw
) {
214 // FIXME the saved data should be corrected instead.
215 if (raw
.indexOf('&') >= 0) {
216 raw
= raw
.replace("&", "&");
218 if (raw
.indexOf('<') >= 0) {
219 raw
= raw
.replace("<", "<");
221 if (raw
.indexOf('>') >= 0) {
222 raw
= raw
.replace(">", ">");
224 if (raw
.indexOf('\"') >= 0) {
225 raw
= raw
.replace("\"", """);
227 if (raw
.indexOf('\'') >= 0) {
228 raw
= raw
.replace("\'", "'");
230 // raw = "<span style='text-align:justify'>" + raw + "</span>";
231 if (raw
.length() == 0)
233 try (StringReader reader
= new StringReader(raw
)) {
234 List
<String
> lines
= IOUtils
.readLines(reader
);
235 if (lines
.size() == 1)
237 StringBuilder sb
= new StringBuilder(raw
.length() + lines
.size() * BR_LENGTH
);
238 for (int i
= 0; i
< lines
.size(); i
++) {
241 sb
.append(lines
.get(i
));
243 return sb
.toString();
247 final static int BR_LENGTH
= "<br/>".length();
249 public String
readSimpleHtml(Item item
) {
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
);
264 * To be overridden, in order to make sure that only valid strings are being
267 protected void validateBeforeStoring(String raw
) {
270 /** To be overridden, in order to support additional formatting. */
271 protected String
convertToStorage(Item item
, String content
) throws RepositoryException
{
276 /** To be overridden, in order to support additional formatting. */
277 protected String
convertFromStorage(Item item
, String content
) throws RepositoryException
{