1 package org
.argeo
.docbook
;
3 import static org
.argeo
.docbook
.DbkType
.para
;
5 import java
.io
.IOException
;
6 import java
.io
.InputStream
;
7 import java
.io
.OutputStream
;
8 import java
.nio
.file
.Files
;
9 import java
.nio
.file
.Path
;
11 import javax
.jcr
.ImportUUIDBehavior
;
12 import javax
.jcr
.Node
;
13 import javax
.jcr
.NodeIterator
;
14 import javax
.jcr
.PathNotFoundException
;
15 import javax
.jcr
.RepositoryException
;
16 import javax
.jcr
.ValueFormatException
;
18 import org
.apache
.commons
.logging
.Log
;
19 import org
.apache
.commons
.logging
.LogFactory
;
20 import org
.argeo
.entity
.EntityType
;
21 import org
.argeo
.jcr
.Jcr
;
22 import org
.argeo
.jcr
.JcrException
;
23 import org
.argeo
.jcr
.JcrUtils
;
24 import org
.argeo
.jcr
.JcrxApi
;
26 /** Utilities around DocBook. */
27 public class DbkUtils
{
28 private final static Log log
= LogFactory
.getLog(DbkUtils
.class);
30 /** Get or add a DocBook element. */
31 public static Node
getOrAddDbk(Node parent
, DbkType child
) {
33 if (!parent
.hasNode(child
.get())) {
34 return addDbk(parent
, child
);
36 return parent
.getNode(child
.get());
38 } catch (RepositoryException e
) {
39 throw new JcrException("Cannot get or add element " + child
.get() + " to " + parent
, e
);
43 /** Add a DocBook element to this node. */
44 public static Node
addDbk(Node parent
, DbkType child
) {
46 Node node
= parent
.addNode(child
.get(), child
.get());
48 } catch (RepositoryException e
) {
49 throw new JcrException("Cannot add element " + child
.get() + " to " + parent
, e
);
53 /** Whether this DocBook element is of this type. */
54 public static boolean isDbk(Node node
, DbkType type
) {
55 return Jcr
.getName(node
).equals(type
.get());
58 /** Whether this node is a DocBook type. */
59 public static boolean isDbk(Node node
) {
60 String name
= Jcr
.getName(node
);
61 for (DbkType type
: DbkType
.values()) {
62 if (name
.equals(type
.get()))
68 public static String
getTitle(Node node
) {
69 return JcrxApi
.getXmlValue(node
, DbkType
.title
.get());
72 public static void setTitle(Node node
, String txt
) {
73 Node titleNode
= getOrAddDbk(node
, DbkType
.title
);
74 JcrxApi
.setXmlValue(node
, titleNode
, txt
);
77 public static Node
getMetadata(Node infoContainer
) {
79 if (!infoContainer
.hasNode(DbkType
.info
.get()))
81 Node info
= infoContainer
.getNode(DbkType
.info
.get());
82 if (!info
.hasNode(EntityType
.local
.get()))
84 return info
.getNode(EntityType
.local
.get());
85 } catch (RepositoryException e
) {
86 throw new JcrException("Cannot retrieve metadata from " + infoContainer
, e
);
90 public static Node
getChildByRole(Node parent
, String role
) {
92 NodeIterator baseSections
= parent
.getNodes();
93 while (baseSections
.hasNext()) {
94 Node n
= baseSections
.nextNode();
95 String r
= Jcr
.get(n
, DbkAttr
.role
.name());
96 if (r
!= null && r
.equals(role
))
100 } catch (RepositoryException e
) {
101 throw new JcrException("Cannot get child from " + parent
+ " with role " + role
, e
);
105 public static Node
addParagraph(Node node
, String txt
) {
106 Node p
= addDbk(node
, para
);
107 JcrxApi
.setXmlValue(node
, p
, txt
);
112 * Removes a paragraph if it empty. The sesison is not saved.
114 * @return true if the paragraph was empty and it was removed
116 public static boolean removeIfEmptyParagraph(Node node
) {
118 if (isDbk(node
, DbkType
.para
)) {
119 NodeIterator nit
= node
.getNodes();
120 if (!nit
.hasNext()) {
124 Node first
= nit
.nextNode();
127 if (first
.getName().equals(Jcr
.JCR_XMLTEXT
)) {
128 String str
= JcrxApi
.getXmlValue(first
);
129 if (str
!= null && str
.trim().equals("")) {
138 } catch (RepositoryException e
) {
139 throw new JcrException("Cannot remove possibly empty paragraph", e
);
143 public static Node
insertImageAfter(Node sibling
) {
146 Node parent
= sibling
.getParent();
147 Node mediaNode
= addDbk(parent
, DbkType
.mediaobject
);
149 parent
.orderBefore(mediaNode
.getName() + "[" + mediaNode
.getIndex() + "]",
150 sibling
.getName() + "[" + sibling
.getIndex() + "]");
151 parent
.orderBefore(sibling
.getName() + "[" + sibling
.getIndex() + "]",
152 mediaNode
.getName() + "[" + mediaNode
.getIndex() + "]");
154 Node imageNode
= addDbk(mediaNode
, DbkType
.imageobject
);
155 Node imageDataNode
= addDbk(imageNode
, DbkType
.imagedata
);
156 // Node infoNode = imageNode.addNode(DocBookTypes.INFO, DocBookTypes.INFO);
157 // Node fileNode = JcrUtils.copyBytesAsFile(mediaFolder, EntityType.box.get(), new byte[0]);
158 // fileNode.addMixin(EntityType.box.get());
159 // fileNode.setProperty(EntityNames.SVG_WIDTH, 0);
160 // fileNode.setProperty(EntityNames.SVG_LENGTH, 0);
161 // fileNode.addMixin(NodeType.MIX_MIMETYPE);
163 // // we assume this is a folder next to the main DocBook document
164 // // TODO make it more robust and generic
165 // String fileRef = mediaNode.getName();
166 // imageDataNode.setProperty(DocBookNames.DBK_FILEREF, fileRef);
168 } catch (RepositoryException e
) {
169 throw new JcrException("Cannot insert empty image after " + sibling
, e
);
173 public static Node
insertVideoAfter(Node sibling
) {
176 Node parent
= sibling
.getParent();
177 Node mediaNode
= addDbk(parent
, DbkType
.mediaobject
);
179 parent
.orderBefore(mediaNode
.getName() + "[" + mediaNode
.getIndex() + "]",
180 sibling
.getName() + "[" + sibling
.getIndex() + "]");
181 parent
.orderBefore(sibling
.getName() + "[" + sibling
.getIndex() + "]",
182 mediaNode
.getName() + "[" + mediaNode
.getIndex() + "]");
184 Node videoNode
= addDbk(mediaNode
, DbkType
.videoobject
);
185 Node videoDataNode
= addDbk(videoNode
, DbkType
.videodata
);
187 } catch (RepositoryException e
) {
188 throw new JcrException("Cannot insert empty image after " + sibling
, e
);
192 public static String
getMediaFileref(Node node
) {
195 if (node
.hasNode(DbkType
.imageobject
.get())) {
196 mediadata
= node
.getNode(DbkType
.imageobject
.get()).getNode(DbkType
.imagedata
.get());
197 } else if (node
.hasNode(DbkType
.videoobject
.get())) {
198 mediadata
= node
.getNode(DbkType
.videoobject
.get()).getNode(DbkType
.videodata
.get());
200 throw new IllegalArgumentException("Fileref not found in " + node
);
203 if (mediadata
.hasProperty(DbkAttr
.fileref
.name())) {
204 return mediadata
.getProperty(DbkAttr
.fileref
.name()).getString();
208 } catch (RepositoryException e
) {
209 throw new JcrException("Cannot retrieve file ref from " + node
, e
);
213 public static void exportXml(Node node
, OutputStream out
) throws IOException
{
215 node
.getSession().exportDocumentView(node
.getPath(), out
, false, false);
216 } catch (RepositoryException e
) {
217 throw new JcrException("Cannot export " + node
+ " to XML", e
);
221 public static void exportToFs(Node baseNode
, DbkType type
, Path directory
) {
222 String fileName
= Jcr
.getName(baseNode
) + ".dbk.xml";
223 Path filePath
= directory
.resolve(fileName
);
224 Node docBookNode
= Jcr
.getNode(baseNode
, type
.get());
225 if (docBookNode
== null)
226 throw new IllegalArgumentException("No " + type
.get() + " under " + baseNode
);
228 Files
.createDirectories(directory
);
229 try (OutputStream out
= Files
.newOutputStream(filePath
)) {
230 exportXml(docBookNode
, out
);
232 JcrUtils
.copyFilesToFs(baseNode
, directory
, true);
233 if (log
.isDebugEnabled())
234 log
.debug("DocBook " + baseNode
+ " exported to " + filePath
.toAbsolutePath());
235 } catch (IOException e
) {
236 throw new RuntimeException(e
);
240 public static void importXml(Node baseNode
, InputStream in
) throws IOException
{
242 baseNode
.getSession().importXML(baseNode
.getPath(), in
,
243 ImportUUIDBehavior
.IMPORT_UUID_COLLISION_REPLACE_EXISTING
);
244 } catch (RepositoryException e
) {
245 throw new JcrException("Cannot import XML to " + baseNode
, e
);