1 package org
.argeo
.app
.jcr
.docbook
;
3 import static org
.argeo
.app
.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
.RepositoryException
;
16 import org
.argeo
.api
.cms
.CmsLog
;
17 import org
.argeo
.app
.api
.EntityType
;
18 import org
.argeo
.app
.docbook
.DbkAttr
;
19 import org
.argeo
.app
.docbook
.DbkType
;
20 import org
.argeo
.jcr
.Jcr
;
21 import org
.argeo
.jcr
.JcrException
;
22 import org
.argeo
.jcr
.JcrUtils
;
23 import org
.argeo
.jcr
.JcrxApi
;
25 /** JCR utilities around DocBook. */
26 public class DbkJcrUtils
{
27 private final static CmsLog log
= CmsLog
.getLog(DbkJcrUtils
.class);
29 /** Get or add a DocBook element. */
30 public static Node
getOrAddDbk(Node parent
, DbkType child
) {
32 if (!parent
.hasNode(child
.get())) {
33 return addDbk(parent
, child
);
35 return parent
.getNode(child
.get());
37 } catch (RepositoryException e
) {
38 throw new JcrException("Cannot get or add element " + child
.get() + " to " + parent
, e
);
42 /** Add a DocBook element to this node. */
43 public static Node
addDbk(Node parent
, DbkType child
) {
45 Node node
= parent
.addNode(child
.get(), child
.get());
47 } catch (RepositoryException e
) {
48 throw new JcrException("Cannot add element " + child
.get() + " to " + parent
, e
);
52 /** Whether this DocBook element is of this type. */
53 public static boolean isDbk(Node node
, DbkType type
) {
54 return Jcr
.getName(node
).equals(type
.get());
57 /** Whether this node is a DocBook type. */
58 public static boolean isDbk(Node node
) {
59 String name
= Jcr
.getName(node
);
60 for (DbkType type
: DbkType
.values()) {
61 if (name
.equals(type
.get()))
67 public static String
getTitle(Node node
) {
68 return JcrxApi
.getXmlValue(node
, DbkType
.title
.get());
71 public static void setTitle(Node node
, String txt
) {
72 Node titleNode
= getOrAddDbk(node
, DbkType
.title
);
73 JcrxApi
.setXmlValue(titleNode
, txt
);
76 public static Node
getMetadata(Node infoContainer
) {
78 if (!infoContainer
.hasNode(DbkType
.info
.get()))
80 Node info
= infoContainer
.getNode(DbkType
.info
.get());
81 if (!info
.hasNode(EntityType
.local
.get()))
83 return info
.getNode(EntityType
.local
.get());
84 } catch (RepositoryException e
) {
85 throw new JcrException("Cannot retrieve metadata from " + infoContainer
, e
);
89 public static Node
getChildByRole(Node parent
, String role
) {
91 NodeIterator baseSections
= parent
.getNodes();
92 while (baseSections
.hasNext()) {
93 Node n
= baseSections
.nextNode();
94 String r
= Jcr
.get(n
, DbkAttr
.role
.name());
95 if (r
!= null && r
.equals(role
))
99 } catch (RepositoryException e
) {
100 throw new JcrException("Cannot get child from " + parent
+ " with role " + role
, e
);
104 public static Node
addParagraph(Node node
, String txt
) {
105 Node p
= addDbk(node
, para
);
106 JcrxApi
.setXmlValue(p
, txt
);
111 * Removes a paragraph if it empty. The sesison is not saved.
113 * @return true if the paragraph was empty and it was removed
115 public static boolean removeIfEmptyParagraph(Node node
) {
117 if (isDbk(node
, DbkType
.para
)) {
118 NodeIterator nit
= node
.getNodes();
119 if (!nit
.hasNext()) {
123 Node first
= nit
.nextNode();
126 if (first
.getName().equals(Jcr
.JCR_XMLTEXT
)) {
127 String str
= Jcr
.get(first
, Jcr
.JCR_XMLCHARACTERS
);
128 if (str
!= null && str
.trim().equals("")) {
137 } catch (RepositoryException e
) {
138 throw new JcrException("Cannot remove possibly empty paragraph", e
);
142 public static Node
insertImageAfter(Node sibling
) {
145 Node parent
= sibling
.getParent();
146 Node mediaNode
= addDbk(parent
, DbkType
.mediaobject
);
148 parent
.orderBefore(mediaNode
.getName() + "[" + mediaNode
.getIndex() + "]",
149 sibling
.getName() + "[" + sibling
.getIndex() + "]");
150 parent
.orderBefore(sibling
.getName() + "[" + sibling
.getIndex() + "]",
151 mediaNode
.getName() + "[" + mediaNode
.getIndex() + "]");
153 Node imageNode
= addDbk(mediaNode
, DbkType
.imageobject
);
154 Node imageDataNode
= addDbk(imageNode
, DbkType
.imagedata
);
155 // Node infoNode = imageNode.addNode(DocBookTypes.INFO, DocBookTypes.INFO);
156 // Node fileNode = JcrUtils.copyBytesAsFile(mediaFolder, EntityType.box.get(), new byte[0]);
157 // fileNode.addMixin(EntityType.box.get());
158 // fileNode.setProperty(EntityNames.SVG_WIDTH, 0);
159 // fileNode.setProperty(EntityNames.SVG_LENGTH, 0);
160 // fileNode.addMixin(NodeType.MIX_MIMETYPE);
162 // // we assume this is a folder next to the main DocBook document
163 // // TODO make it more robust and generic
164 // String fileRef = mediaNode.getName();
165 // imageDataNode.setProperty(DocBookNames.DBK_FILEREF, fileRef);
167 } catch (RepositoryException e
) {
168 throw new JcrException("Cannot insert empty image after " + sibling
, e
);
172 public static Node
insertVideoAfter(Node sibling
) {
175 Node parent
= sibling
.getParent();
176 Node mediaNode
= addDbk(parent
, DbkType
.mediaobject
);
178 parent
.orderBefore(mediaNode
.getName() + "[" + mediaNode
.getIndex() + "]",
179 sibling
.getName() + "[" + sibling
.getIndex() + "]");
180 parent
.orderBefore(sibling
.getName() + "[" + sibling
.getIndex() + "]",
181 mediaNode
.getName() + "[" + mediaNode
.getIndex() + "]");
183 Node videoNode
= addDbk(mediaNode
, DbkType
.videoobject
);
184 Node videoDataNode
= addDbk(videoNode
, DbkType
.videodata
);
186 } catch (RepositoryException e
) {
187 throw new JcrException("Cannot insert empty image after " + sibling
, e
);
191 public static String
getMediaFileref(Node node
) {
194 if (node
.hasNode(DbkType
.imageobject
.get())) {
195 mediadata
= node
.getNode(DbkType
.imageobject
.get()).getNode(DbkType
.imagedata
.get());
196 } else if (node
.hasNode(DbkType
.videoobject
.get())) {
197 mediadata
= node
.getNode(DbkType
.videoobject
.get()).getNode(DbkType
.videodata
.get());
199 throw new IllegalArgumentException("Fileref not found in " + node
);
202 if (mediadata
.hasProperty(DbkAttr
.fileref
.name())) {
203 return mediadata
.getProperty(DbkAttr
.fileref
.name()).getString();
207 } catch (RepositoryException e
) {
208 throw new JcrException("Cannot retrieve file ref from " + node
, e
);
212 public static void exportXml(Node node
, OutputStream out
) throws IOException
{
214 node
.getSession().exportDocumentView(node
.getPath(), out
, false, false);
215 } catch (RepositoryException e
) {
216 throw new JcrException("Cannot export " + node
+ " to XML", e
);
220 public static void exportToFs(Node baseNode
, DbkType type
, Path directory
) {
221 String fileName
= Jcr
.getName(baseNode
) + ".dbk.xml";
222 Path filePath
= directory
.resolve(fileName
);
223 Node docBookNode
= Jcr
.getNode(baseNode
, type
.get());
224 if (docBookNode
== null)
225 throw new IllegalArgumentException("No " + type
.get() + " under " + baseNode
);
227 Files
.createDirectories(directory
);
228 try (OutputStream out
= Files
.newOutputStream(filePath
)) {
229 exportXml(docBookNode
, out
);
231 JcrUtils
.copyFilesToFs(baseNode
, directory
, true);
232 if (log
.isDebugEnabled())
233 log
.debug("DocBook " + baseNode
+ " exported to " + filePath
.toAbsolutePath());
234 } catch (IOException e
) {
235 throw new RuntimeException(e
);
239 public static void importXml(Node baseNode
, InputStream in
) throws IOException
{
241 baseNode
.getSession().importXML(baseNode
.getPath(), in
,
242 ImportUUIDBehavior
.IMPORT_UUID_COLLISION_REPLACE_EXISTING
);
243 } catch (RepositoryException e
) {
244 throw new JcrException("Cannot import XML to " + baseNode
, e
);
250 private DbkJcrUtils() {