1 package org
.argeo
.maintenance
.backup
;
3 import java
.io
.IOException
;
4 import java
.io
.InputStream
;
6 import java
.util
.Base64
;
8 import java
.util
.TreeSet
;
10 import javax
.jcr
.Binary
;
11 import javax
.jcr
.RepositoryException
;
12 import javax
.jcr
.Session
;
14 import org
.apache
.commons
.io
.IOUtils
;
15 import org
.argeo
.jcr
.JcrException
;
16 import org
.xml
.sax
.Attributes
;
17 import org
.xml
.sax
.SAXException
;
18 import org
.xml
.sax
.helpers
.DefaultHandler
;
20 /** XML handler serialising a JCR system view. */
21 public class BackupContentHandler
extends DefaultHandler
{
22 final static int MAX_DEPTH
= 1024;
23 final static String SV_NAMESPACE_URI
= "http://www.jcp.org/jcr/sv/1.0";
24 final static String SV_PREFIX
= "sv";
26 final static String NODE
= "node";
27 final static String PROPERTY
= "property";
28 final static String VALUE
= "value";
30 final static String NAME
= "name";
31 final static String MULTIPLE
= "multiple";
32 final static String TYPE
= "type";
35 final static String BINARY
= "Binary";
36 final static String JCR_CONTENT
= "jcr:content";
39 private Session session
;
40 private Set
<String
> contentPaths
= new TreeSet
<>();
42 private boolean inSystem
= false;
44 public BackupContentHandler(Writer out
, Session session
) {
47 this.session
= session
;
50 private int currentDepth
= -1;
51 private String
[] currentPath
= new String
[MAX_DEPTH
];
53 private boolean currentPropertyIsMultiple
= false;
54 private String currentEncoded
= null;
55 private Base64
.Encoder base64encore
= Base64
.getEncoder();
58 public void startElement(String uri
, String localName
, String qName
, Attributes attributes
) throws SAXException
{
76 String nodeName
= attributes
.getValue(SV_NAMESPACE_URI
, NAME
);
77 currentDepth
= currentDepth
+ 1;
79 currentPath
[currentDepth
- 1] = nodeName
;
80 // System.out.println(getCurrentPath() + " , depth=" + currentDepth);
81 if ("jcr:system".equals(nodeName
)) {
88 if (SV_NAMESPACE_URI
.equals(uri
))
91 out
.write(SV_PREFIX
+ ":" + localName
);
93 currentPropertyIsMultiple
= false; // always reset
94 for (int i
= 0; i
< attributes
.getLength(); i
++) {
95 String ns
= attributes
.getURI(i
);
96 if (SV_NAMESPACE_URI
.equals(ns
)) {
97 String attrName
= attributes
.getLocalName(i
);
98 String attrValue
= attributes
.getValue(i
);
100 out
.write(SV_PREFIX
+ ":" + attrName
);
103 out
.write(attrValue
);
106 if (MULTIPLE
.equals(attrName
))
107 currentPropertyIsMultiple
= Boolean
.parseBoolean(attrValue
);
108 else if (TYPE
.equals(attrName
)) {
109 if (BINARY
.equals(attrValue
)) {
110 if (JCR_CONTENT
.equals(getCurrentName())) {
111 contentPaths
.add(getCurrentPath());
113 Binary binary
= session
.getNode(getCurrentPath()).getProperty(attrName
)
115 try (InputStream in
= binary
.getStream()) {
116 currentEncoded
= base64encore
.encodeToString(IOUtils
.toByteArray(in
));
126 if (isNode
&& currentDepth
== 0) {
127 // out.write(" xmlns=\"" + SV_NAMESPACE_URI + "\"");
128 out
.write(" xmlns:" + SV_PREFIX
+ "=\"" + SV_NAMESPACE_URI
+ "\"");
133 else if (isProperty
&& currentPropertyIsMultiple
)
135 } catch (IOException e
) {
136 throw new RuntimeException(e
);
137 } catch (RepositoryException e
) {
138 throw new JcrException(e
);
143 public void endElement(String uri
, String localName
, String qName
) throws SAXException
{
144 if (localName
.equals(NODE
)) {
145 // System.out.println("endElement " + getCurrentPath() + " , depth=" + currentDepth);
146 if (currentDepth
> 0)
147 currentPath
[currentDepth
- 1] = null;
148 currentDepth
= currentDepth
- 1;
150 // System.out.println("Skip " + getCurrentPath()+" ,
151 // currentDepth="+currentDepth);
152 if (currentDepth
== 0) {
160 boolean isValue
= localName
.equals(VALUE
);
161 if (SV_NAMESPACE_URI
.equals(uri
))
163 if (isValue
&& currentEncoded
!= null) {
164 out
.write(currentEncoded
);
166 currentEncoded
= null;
168 out
.write(SV_PREFIX
+ ":" + localName
);
173 if (currentPropertyIsMultiple
)
176 } catch (IOException e
) {
177 throw new RuntimeException(e
);
182 public void characters(char[] ch
, int start
, int length
) throws SAXException
{
186 out
.write(ch
, start
, length
);
187 } catch (IOException e
) {
188 throw new RuntimeException(e
);
192 protected String
getCurrentName() {
193 assert currentDepth
>= 0;
194 if (currentDepth
== 0)
196 return currentPath
[currentDepth
- 1];
199 protected String
getCurrentPath() {
200 if (currentDepth
== 0)
202 StringBuilder sb
= new StringBuilder("/");
203 for (int i
= 0; i
< currentDepth
; i
++) {
206 sb
.append(currentPath
[i
]);
208 return sb
.toString();
211 public Set
<String
> getContentPaths() {