Improve media management in DocBook.
[gpl/argeo-suite.git] / publishing / org.argeo.publishing.ui / src / org / argeo / docbook / DbkUtils.java
1 package org.argeo.docbook;
2
3 import static org.argeo.docbook.DbkType.para;
4
5 import java.io.IOException;
6 import java.io.OutputStream;
7 import java.nio.file.Files;
8 import java.nio.file.Path;
9
10 import javax.jcr.Node;
11 import javax.jcr.NodeIterator;
12 import javax.jcr.RepositoryException;
13
14 import org.apache.commons.logging.Log;
15 import org.apache.commons.logging.LogFactory;
16 import org.argeo.entity.EntityType;
17 import org.argeo.jcr.Jcr;
18 import org.argeo.jcr.JcrException;
19 import org.argeo.jcr.JcrUtils;
20 import org.argeo.jcr.JcrxApi;
21
22 /** Utilities around DocBook. */
23 public class DbkUtils {
24         private final static Log log = LogFactory.getLog(DbkUtils.class);
25
26         /** Get or add a DocBook element. */
27         public static Node getOrAddDbk(Node parent, DbkType child) {
28                 try {
29                         if (!parent.hasNode(child.get())) {
30                                 return addDbk(parent, child);
31                         } else {
32                                 return parent.getNode(child.get());
33                         }
34                 } catch (RepositoryException e) {
35                         throw new JcrException("Cannot get or add element " + child.get() + " to " + parent, e);
36                 }
37         }
38
39         /** Add a DocBook element to this node. */
40         public static Node addDbk(Node parent, DbkType child) {
41                 try {
42                         Node node = parent.addNode(child.get(), child.get());
43                         return node;
44                 } catch (RepositoryException e) {
45                         throw new JcrException("Cannot add element " + child.get() + " to " + parent, e);
46                 }
47         }
48
49         /** Whether this DocBook element is of this type. */
50         public static boolean isDbk(Node node, DbkType type) {
51                 return Jcr.getName(node).equals(type.get());
52         }
53
54         public static String getTitle(Node node) {
55                 return JcrxApi.getXmlValue(node, DbkType.title.get());
56         }
57
58         public static void setTitle(Node node, String txt) {
59                 Node titleNode = getOrAddDbk(node, DbkType.title);
60                 JcrxApi.setXmlValue(node, titleNode, txt);
61         }
62
63         public static Node getMetadata(Node infoContainer) {
64                 try {
65                         if (!infoContainer.hasNode(DbkType.info.get()))
66                                 return null;
67                         Node info = infoContainer.getNode(DbkType.info.get());
68                         if (!info.hasNode(EntityType.local.get()))
69                                 return null;
70                         return info.getNode(EntityType.local.get());
71                 } catch (RepositoryException e) {
72                         throw new JcrException("Cannot retrieve metadata from " + infoContainer, e);
73                 }
74         }
75
76         public static Node getChildByRole(Node parent, String role) {
77                 try {
78                         NodeIterator baseSections = parent.getNodes();
79                         while (baseSections.hasNext()) {
80                                 Node n = baseSections.nextNode();
81                                 String r = Jcr.get(n, DbkAttr.role.name());
82                                 if (r != null && r.equals(role))
83                                         return n;
84                         }
85                         return null;
86                 } catch (RepositoryException e) {
87                         throw new JcrException("Cannot get child from " + parent + " with role " + role, e);
88                 }
89         }
90
91         public static Node addParagraph(Node node, String txt) {
92                 Node p = addDbk(node, para);
93                 JcrxApi.setXmlValue(node, p, txt);
94                 return p;
95         }
96
97         public static Node insertImageAfter(Node sibling) {
98                 try {
99
100                         Node parent = sibling.getParent();
101                         Node mediaNode = addDbk(parent, DbkType.mediaobject);
102                         // TODO optimise?
103                         parent.orderBefore(mediaNode.getName() + "[" + mediaNode.getIndex() + "]",
104                                         sibling.getName() + "[" + sibling.getIndex() + "]");
105                         parent.orderBefore(sibling.getName() + "[" + sibling.getIndex() + "]",
106                                         mediaNode.getName() + "[" + mediaNode.getIndex() + "]");
107
108                         Node imageNode = addDbk(mediaNode, DbkType.imageobject);
109                         Node imageDataNode = addDbk(imageNode, DbkType.imagedata);
110 //                      Node infoNode = imageNode.addNode(DocBookTypes.INFO, DocBookTypes.INFO);
111 //                      Node fileNode = JcrUtils.copyBytesAsFile(mediaFolder, EntityType.box.get(), new byte[0]);
112 //                      fileNode.addMixin(EntityType.box.get());
113 //                      fileNode.setProperty(EntityNames.SVG_WIDTH, 0);
114 //                      fileNode.setProperty(EntityNames.SVG_LENGTH, 0);
115 //                      fileNode.addMixin(NodeType.MIX_MIMETYPE);
116 //
117 //                      // we assume this is a folder next to the main DocBook document
118 //                      // TODO make it more robust and generic
119 //                      String fileRef = mediaNode.getName();
120 //                      imageDataNode.setProperty(DocBookNames.DBK_FILEREF, fileRef);
121                         return mediaNode;
122                 } catch (RepositoryException e) {
123                         throw new JcrException("Cannot insert empty image after " + sibling, e);
124                 }
125         }
126
127         public static void exportXml(Node node, OutputStream out) throws IOException {
128                 try {
129                         node.getSession().exportDocumentView(node.getPath(), out, false, false);
130                 } catch (RepositoryException e) {
131                         throw new JcrException("Cannot export " + node + " to XML", e);
132                 }
133         }
134
135         public static void exportToFs(Node baseNode, DbkType type, Path directory) {
136                 String fileName = Jcr.getName(baseNode) + ".dbk.xml";
137                 Path filePath = directory.resolve(fileName);
138                 Node docBookNode = Jcr.getNode(baseNode, type.get());
139                 if (docBookNode == null)
140                         throw new IllegalArgumentException("No " + type.get() + " under " + baseNode);
141                 try {
142                         Files.createDirectories(directory);
143                         try (OutputStream out = Files.newOutputStream(filePath)) {
144                                 exportXml(docBookNode, out);
145                         }
146                         JcrUtils.copyFilesToFs(baseNode, directory, true);
147                         if (log.isDebugEnabled())
148                                 log.debug("DocBook " + baseNode + " exported to " + filePath.toAbsolutePath());
149                 } catch (IOException e) {
150                         throw new RuntimeException(e);
151                 }
152         }
153
154         /** Singleton. */
155         private DbkUtils() {
156         }
157
158 }