X-Git-Url: https://git.argeo.org/?p=gpl%2Fargeo-suite.git;a=blobdiff_plain;f=org.argeo.app.core%2Fsrc%2Forg%2Fargeo%2Fapp%2Fdocbook%2FDbkUtils.java;fp=org.argeo.app.core%2Fsrc%2Forg%2Fargeo%2Fapp%2Fdocbook%2FDbkUtils.java;h=6c959f43d3269c3e90287e508abb918564db08ed;hp=0000000000000000000000000000000000000000;hb=6e56ffa34cb02ab04d028423aea342e3dfed4358;hpb=c285180bece610b2c2921d44fe14b6dde2123efa diff --git a/org.argeo.app.core/src/org/argeo/app/docbook/DbkUtils.java b/org.argeo.app.core/src/org/argeo/app/docbook/DbkUtils.java new file mode 100644 index 0000000..6c959f4 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/docbook/DbkUtils.java @@ -0,0 +1,253 @@ +package org.argeo.app.docbook; + +import static org.argeo.app.docbook.DbkType.para; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; + +import javax.jcr.ImportUUIDBehavior; +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.PathNotFoundException; +import javax.jcr.RepositoryException; +import javax.jcr.ValueFormatException; + +import org.argeo.api.cms.CmsLog; +import org.argeo.app.api.EntityType; +import org.argeo.jcr.Jcr; +import org.argeo.jcr.JcrException; +import org.argeo.jcr.JcrUtils; +import org.argeo.jcr.JcrxApi; + +/** Utilities around DocBook. */ +public class DbkUtils { + private final static CmsLog log = CmsLog.getLog(DbkUtils.class); + + /** Get or add a DocBook element. */ + public static Node getOrAddDbk(Node parent, DbkType child) { + try { + if (!parent.hasNode(child.get())) { + return addDbk(parent, child); + } else { + return parent.getNode(child.get()); + } + } catch (RepositoryException e) { + throw new JcrException("Cannot get or add element " + child.get() + " to " + parent, e); + } + } + + /** Add a DocBook element to this node. */ + public static Node addDbk(Node parent, DbkType child) { + try { + Node node = parent.addNode(child.get(), child.get()); + return node; + } catch (RepositoryException e) { + throw new JcrException("Cannot add element " + child.get() + " to " + parent, e); + } + } + + /** Whether this DocBook element is of this type. */ + public static boolean isDbk(Node node, DbkType type) { + return Jcr.getName(node).equals(type.get()); + } + + /** Whether this node is a DocBook type. */ + public static boolean isDbk(Node node) { + String name = Jcr.getName(node); + for (DbkType type : DbkType.values()) { + if (name.equals(type.get())) + return true; + } + return false; + } + + public static String getTitle(Node node) { + return JcrxApi.getXmlValue(node, DbkType.title.get()); + } + + public static void setTitle(Node node, String txt) { + Node titleNode = getOrAddDbk(node, DbkType.title); + JcrxApi.setXmlValue(node, titleNode, txt); + } + + public static Node getMetadata(Node infoContainer) { + try { + if (!infoContainer.hasNode(DbkType.info.get())) + return null; + Node info = infoContainer.getNode(DbkType.info.get()); + if (!info.hasNode(EntityType.local.get())) + return null; + return info.getNode(EntityType.local.get()); + } catch (RepositoryException e) { + throw new JcrException("Cannot retrieve metadata from " + infoContainer, e); + } + } + + public static Node getChildByRole(Node parent, String role) { + try { + NodeIterator baseSections = parent.getNodes(); + while (baseSections.hasNext()) { + Node n = baseSections.nextNode(); + String r = Jcr.get(n, DbkAttr.role.name()); + if (r != null && r.equals(role)) + return n; + } + return null; + } catch (RepositoryException e) { + throw new JcrException("Cannot get child from " + parent + " with role " + role, e); + } + } + + public static Node addParagraph(Node node, String txt) { + Node p = addDbk(node, para); + JcrxApi.setXmlValue(node, p, txt); + return p; + } + + /** + * Removes a paragraph if it empty. The sesison is not saved. + * + * @return true if the paragraph was empty and it was removed + */ + public static boolean removeIfEmptyParagraph(Node node) { + try { + if (isDbk(node, DbkType.para)) { + NodeIterator nit = node.getNodes(); + if (!nit.hasNext()) { + node.remove(); + return true; + } + Node first = nit.nextNode(); + if (nit.hasNext()) + return false; + if (first.getName().equals(Jcr.JCR_XMLTEXT)) { + String str = Jcr.get(first, Jcr.JCR_XMLCHARACTERS); + if (str != null && str.trim().equals("")) { + node.remove(); + return true; + } + } else { + return false; + } + } + return false; + } catch (RepositoryException e) { + throw new JcrException("Cannot remove possibly empty paragraph", e); + } + } + + public static Node insertImageAfter(Node sibling) { + try { + + Node parent = sibling.getParent(); + Node mediaNode = addDbk(parent, DbkType.mediaobject); + // TODO optimise? + parent.orderBefore(mediaNode.getName() + "[" + mediaNode.getIndex() + "]", + sibling.getName() + "[" + sibling.getIndex() + "]"); + parent.orderBefore(sibling.getName() + "[" + sibling.getIndex() + "]", + mediaNode.getName() + "[" + mediaNode.getIndex() + "]"); + + Node imageNode = addDbk(mediaNode, DbkType.imageobject); + Node imageDataNode = addDbk(imageNode, DbkType.imagedata); +// Node infoNode = imageNode.addNode(DocBookTypes.INFO, DocBookTypes.INFO); +// Node fileNode = JcrUtils.copyBytesAsFile(mediaFolder, EntityType.box.get(), new byte[0]); +// fileNode.addMixin(EntityType.box.get()); +// fileNode.setProperty(EntityNames.SVG_WIDTH, 0); +// fileNode.setProperty(EntityNames.SVG_LENGTH, 0); +// fileNode.addMixin(NodeType.MIX_MIMETYPE); +// +// // we assume this is a folder next to the main DocBook document +// // TODO make it more robust and generic +// String fileRef = mediaNode.getName(); +// imageDataNode.setProperty(DocBookNames.DBK_FILEREF, fileRef); + return mediaNode; + } catch (RepositoryException e) { + throw new JcrException("Cannot insert empty image after " + sibling, e); + } + } + + public static Node insertVideoAfter(Node sibling) { + try { + + Node parent = sibling.getParent(); + Node mediaNode = addDbk(parent, DbkType.mediaobject); + // TODO optimise? + parent.orderBefore(mediaNode.getName() + "[" + mediaNode.getIndex() + "]", + sibling.getName() + "[" + sibling.getIndex() + "]"); + parent.orderBefore(sibling.getName() + "[" + sibling.getIndex() + "]", + mediaNode.getName() + "[" + mediaNode.getIndex() + "]"); + + Node videoNode = addDbk(mediaNode, DbkType.videoobject); + Node videoDataNode = addDbk(videoNode, DbkType.videodata); + return mediaNode; + } catch (RepositoryException e) { + throw new JcrException("Cannot insert empty image after " + sibling, e); + } + } + + public static String getMediaFileref(Node node) { + try { + Node mediadata; + if (node.hasNode(DbkType.imageobject.get())) { + mediadata = node.getNode(DbkType.imageobject.get()).getNode(DbkType.imagedata.get()); + } else if (node.hasNode(DbkType.videoobject.get())) { + mediadata = node.getNode(DbkType.videoobject.get()).getNode(DbkType.videodata.get()); + } else { + throw new IllegalArgumentException("Fileref not found in " + node); + } + + if (mediadata.hasProperty(DbkAttr.fileref.name())) { + return mediadata.getProperty(DbkAttr.fileref.name()).getString(); + } else { + return null; + } + } catch (RepositoryException e) { + throw new JcrException("Cannot retrieve file ref from " + node, e); + } + } + + public static void exportXml(Node node, OutputStream out) throws IOException { + try { + node.getSession().exportDocumentView(node.getPath(), out, false, false); + } catch (RepositoryException e) { + throw new JcrException("Cannot export " + node + " to XML", e); + } + } + + public static void exportToFs(Node baseNode, DbkType type, Path directory) { + String fileName = Jcr.getName(baseNode) + ".dbk.xml"; + Path filePath = directory.resolve(fileName); + Node docBookNode = Jcr.getNode(baseNode, type.get()); + if (docBookNode == null) + throw new IllegalArgumentException("No " + type.get() + " under " + baseNode); + try { + Files.createDirectories(directory); + try (OutputStream out = Files.newOutputStream(filePath)) { + exportXml(docBookNode, out); + } + JcrUtils.copyFilesToFs(baseNode, directory, true); + if (log.isDebugEnabled()) + log.debug("DocBook " + baseNode + " exported to " + filePath.toAbsolutePath()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static void importXml(Node baseNode, InputStream in) throws IOException { + try { + baseNode.getSession().importXML(baseNode.getPath(), in, + ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING); + } catch (RepositoryException e) { + throw new JcrException("Cannot import XML to " + baseNode, e); + } + + } + + /** Singleton. */ + private DbkUtils() { + } + +}