X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms.jcr%2Fsrc%2Forg%2Fargeo%2Fmaintenance%2Fbackup%2FBackupContentHandler.java;fp=org.argeo.cms.jcr%2Fsrc%2Forg%2Fargeo%2Fmaintenance%2Fbackup%2FBackupContentHandler.java;h=ef83c1ff9f0f393253d9768be790fd131fd99f4f;hb=bce03099b0d2f1758e7a3d74fba339d0200924d5;hp=0000000000000000000000000000000000000000;hpb=0ea2992e5f3803cd98b5981f27274faa922bc199;p=gpl%2Fargeo-jcr.git diff --git a/org.argeo.cms.jcr/src/org/argeo/maintenance/backup/BackupContentHandler.java b/org.argeo.cms.jcr/src/org/argeo/maintenance/backup/BackupContentHandler.java new file mode 100644 index 0000000..ef83c1f --- /dev/null +++ b/org.argeo.cms.jcr/src/org/argeo/maintenance/backup/BackupContentHandler.java @@ -0,0 +1,257 @@ +package org.argeo.maintenance.backup; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Writer; +import java.util.Arrays; +import java.util.Base64; +import java.util.Set; +import java.util.TreeSet; + +import javax.jcr.Binary; +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.apache.commons.io.IOUtils; +import org.argeo.jcr.Jcr; +import org.argeo.jcr.JcrException; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** XML handler serialising a JCR system view. */ +public class BackupContentHandler extends DefaultHandler { + final static int MAX_DEPTH = 1024; + final static String SV_NAMESPACE_URI = "http://www.jcp.org/jcr/sv/1.0"; + final static String SV_PREFIX = "sv"; + // elements + final static String NODE = "node"; + final static String PROPERTY = "property"; + final static String VALUE = "value"; + // attributes + final static String NAME = "name"; + final static String MULTIPLE = "multiple"; + final static String TYPE = "type"; + + // values + final static String BINARY = "Binary"; + final static String JCR_CONTENT = "jcr:content"; + + private Writer out; + private Session session; + private Set contentPaths = new TreeSet<>(); + + boolean prettyPrint = true; + + private final String parentPath; + +// private boolean inSystem = false; + + public BackupContentHandler(Writer out, Node node) { + super(); + this.out = out; + this.session = Jcr.getSession(node); + parentPath = Jcr.getParentPath(node); + } + + private int currentDepth = -1; + private String[] currentPath = new String[MAX_DEPTH]; + + private boolean currentPropertyIsMultiple = false; + private String currentEncoded = null; + private Base64.Encoder base64encore = Base64.getEncoder(); + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + boolean isNode; + boolean isProperty; + switch (localName) { + case NODE: + isNode = true; + isProperty = false; + break; + case PROPERTY: + isNode = false; + isProperty = true; + break; + default: + isNode = false; + isProperty = false; + } + + if (isNode) { + String nodeName = attributes.getValue(SV_NAMESPACE_URI, NAME); + currentDepth = currentDepth + 1; +// if (currentDepth >= 0) + currentPath[currentDepth] = nodeName; +// System.out.println(getCurrentPath() + " , depth=" + currentDepth); +// if ("jcr:system".equals(nodeName)) { +// inSystem = true; +// } + } +// if (inSystem) +// return; + + if (SV_NAMESPACE_URI.equals(uri)) + try { + if (prettyPrint) { + if (isNode) { + out.write(spaces()); + out.write("\n"); + out.write(spaces()); + } else if (isProperty) + out.write(spaces()); + else if (currentPropertyIsMultiple) + out.write(spaces()); + } + + out.write("<"); + out.write(SV_PREFIX + ":" + localName); + if (isProperty) + currentPropertyIsMultiple = false; // always reset + for (int i = 0; i < attributes.getLength(); i++) { + String ns = attributes.getURI(i); + if (SV_NAMESPACE_URI.equals(ns)) { + String attrName = attributes.getLocalName(i); + String attrValue = attributes.getValue(i); + out.write(" "); + out.write(SV_PREFIX + ":" + attrName); + out.write("="); + out.write("\""); + out.write(attrValue); + out.write("\""); + if (isProperty) { + if (MULTIPLE.equals(attrName)) + currentPropertyIsMultiple = Boolean.parseBoolean(attrValue); + else if (TYPE.equals(attrName)) { + if (BINARY.equals(attrValue)) { + if (JCR_CONTENT.equals(getCurrentName())) { + contentPaths.add(getCurrentJcrPath()); + } else { + Binary binary = session.getNode(getCurrentJcrPath()).getProperty(attrName) + .getBinary(); + try (InputStream in = binary.getStream()) { + currentEncoded = base64encore.encodeToString(IOUtils.toByteArray(in)); + } finally { + + } + } + } + } + } + } + } + if (isNode && currentDepth == 0) { + // out.write(" xmlns=\"" + SV_NAMESPACE_URI + "\""); + out.write(" xmlns:" + SV_PREFIX + "=\"" + SV_NAMESPACE_URI + "\""); + } + out.write(">"); + + if (prettyPrint) + if (isNode) + out.write("\n"); + else if (isProperty && currentPropertyIsMultiple) + out.write("\n"); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (RepositoryException e) { + throw new JcrException(e); + } + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + boolean isNode = localName.equals(NODE); + boolean isValue = localName.equals(VALUE); + if (prettyPrint) + if (!isValue) + try { + if (isNode || currentPropertyIsMultiple) + out.write(spaces()); + } catch (IOException e1) { + throw new RuntimeException(e1); + } + if (isNode) { +// System.out.println("endElement " + getCurrentPath() + " , depth=" + currentDepth); +// if (currentDepth > 0) + currentPath[currentDepth] = null; + currentDepth = currentDepth - 1; +// if (inSystem) { +// // System.out.println("Skip " + getCurrentPath()+" , +// // currentDepth="+currentDepth); +// if (currentDepth == 0) { +// inSystem = false; +// return; +// } +// } + } +// if (inSystem) +// return; + if (SV_NAMESPACE_URI.equals(uri)) + try { + if (isValue && currentEncoded != null) { + out.write(currentEncoded); + } + currentEncoded = null; + out.write(""); + if (prettyPrint) + if (!isValue) + out.write("\n"); + else { + if (currentPropertyIsMultiple) + out.write("\n"); + } + if (currentDepth == 0) + out.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + } + + private char[] spaces() { + char[] arr = new char[currentDepth]; + Arrays.fill(arr, ' '); + return arr; + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { +// if (inSystem) +// return; + try { + out.write(ch, start, length); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + protected String getCurrentName() { + assert currentDepth >= 0; +// if (currentDepth == 0) +// return "jcr:root"; + return currentPath[currentDepth]; + } + + protected String getCurrentJcrPath() { +// if (currentDepth == 0) +// return "/"; + StringBuilder sb = new StringBuilder(parentPath.equals("/") ? "" : parentPath); + for (int i = 0; i <= currentDepth; i++) { +// if (i != 0) + sb.append('/'); + sb.append(currentPath[i]); + } + return sb.toString(); + } + + public Set getContentPaths() { + return contentPaths; + } + +}