1 package org
.argeo
.maintenance
.backup
;
3 import java
.io
.IOException
;
4 import java
.io
.InputStream
;
6 import java
.util
.Arrays
;
7 import java
.util
.Base64
;
9 import java
.util
.TreeSet
;
11 import javax
.jcr
.Binary
;
12 import javax
.jcr
.Node
;
13 import javax
.jcr
.RepositoryException
;
14 import javax
.jcr
.Session
;
16 import org
.apache
.commons
.io
.IOUtils
;
17 import org
.argeo
.jcr
.Jcr
;
18 import org
.argeo
.jcr
.JcrException
;
19 import org
.xml
.sax
.Attributes
;
20 import org
.xml
.sax
.SAXException
;
21 import org
.xml
.sax
.helpers
.DefaultHandler
;
23 /** XML handler serialising a JCR system view. */
24 public class BackupContentHandler
extends DefaultHandler
{
25 final static int MAX_DEPTH
= 1024;
26 final static String SV_NAMESPACE_URI
= "http://www.jcp.org/jcr/sv/1.0";
27 final static String SV_PREFIX
= "sv";
29 final static String NODE
= "node";
30 final static String PROPERTY
= "property";
31 final static String VALUE
= "value";
33 final static String NAME
= "name";
34 final static String MULTIPLE
= "multiple";
35 final static String TYPE
= "type";
38 final static String BINARY
= "Binary";
39 final static String JCR_CONTENT
= "jcr:content";
42 private Session session
;
43 private Set
<String
> contentPaths
= new TreeSet
<>();
45 boolean prettyPrint
= true;
47 private final String parentPath
;
49 // private boolean inSystem = false;
51 public BackupContentHandler(Writer out
, Node node
) {
54 this.session
= Jcr
.getSession(node
);
55 parentPath
= Jcr
.getParentPath(node
);
58 private int currentDepth
= -1;
59 private String
[] currentPath
= new String
[MAX_DEPTH
];
61 private boolean currentPropertyIsMultiple
= false;
62 private String currentEncoded
= null;
63 private Base64
.Encoder base64encore
= Base64
.getEncoder();
66 public void startElement(String uri
, String localName
, String qName
, Attributes attributes
) throws SAXException
{
84 String nodeName
= attributes
.getValue(SV_NAMESPACE_URI
, NAME
);
85 currentDepth
= currentDepth
+ 1;
86 // if (currentDepth >= 0)
87 currentPath
[currentDepth
] = nodeName
;
88 // System.out.println(getCurrentPath() + " , depth=" + currentDepth);
89 // if ("jcr:system".equals(nodeName)) {
96 if (SV_NAMESPACE_URI
.equals(uri
))
102 out
.write(getCurrentJcrPath());
105 } else if (isProperty
)
107 else if (currentPropertyIsMultiple
)
112 out
.write(SV_PREFIX
+ ":" + localName
);
114 currentPropertyIsMultiple
= false; // always reset
115 for (int i
= 0; i
< attributes
.getLength(); i
++) {
116 String ns
= attributes
.getURI(i
);
117 if (SV_NAMESPACE_URI
.equals(ns
)) {
118 String attrName
= attributes
.getLocalName(i
);
119 String attrValue
= attributes
.getValue(i
);
121 out
.write(SV_PREFIX
+ ":" + attrName
);
124 out
.write(attrValue
);
127 if (MULTIPLE
.equals(attrName
))
128 currentPropertyIsMultiple
= Boolean
.parseBoolean(attrValue
);
129 else if (TYPE
.equals(attrName
)) {
130 if (BINARY
.equals(attrValue
)) {
131 if (JCR_CONTENT
.equals(getCurrentName())) {
132 contentPaths
.add(getCurrentJcrPath());
134 Binary binary
= session
.getNode(getCurrentJcrPath()).getProperty(attrName
)
136 try (InputStream in
= binary
.getStream()) {
137 currentEncoded
= base64encore
.encodeToString(IOUtils
.toByteArray(in
));
147 if (isNode
&& currentDepth
== 0) {
148 // out.write(" xmlns=\"" + SV_NAMESPACE_URI + "\"");
149 out
.write(" xmlns:" + SV_PREFIX
+ "=\"" + SV_NAMESPACE_URI
+ "\"");
156 else if (isProperty
&& currentPropertyIsMultiple
)
158 } catch (IOException e
) {
159 throw new RuntimeException(e
);
160 } catch (RepositoryException e
) {
161 throw new JcrException(e
);
166 public void endElement(String uri
, String localName
, String qName
) throws SAXException
{
167 boolean isNode
= localName
.equals(NODE
);
168 boolean isValue
= localName
.equals(VALUE
);
172 if (isNode
|| currentPropertyIsMultiple
)
174 } catch (IOException e1
) {
175 throw new RuntimeException(e1
);
178 // System.out.println("endElement " + getCurrentPath() + " , depth=" + currentDepth);
179 // if (currentDepth > 0)
180 currentPath
[currentDepth
] = null;
181 currentDepth
= currentDepth
- 1;
183 // // System.out.println("Skip " + getCurrentPath()+" ,
184 // // currentDepth="+currentDepth);
185 // if (currentDepth == 0) {
193 if (SV_NAMESPACE_URI
.equals(uri
))
195 if (isValue
&& currentEncoded
!= null) {
196 out
.write(currentEncoded
);
198 currentEncoded
= null;
200 out
.write(SV_PREFIX
+ ":" + localName
);
206 if (currentPropertyIsMultiple
)
209 if (currentDepth
== 0)
211 } catch (IOException e
) {
212 throw new RuntimeException(e
);
217 private char[] spaces() {
218 char[] arr
= new char[currentDepth
];
219 Arrays
.fill(arr
, ' ');
224 public void characters(char[] ch
, int start
, int length
) throws SAXException
{
228 out
.write(ch
, start
, length
);
229 } catch (IOException e
) {
230 throw new RuntimeException(e
);
234 protected String
getCurrentName() {
235 assert currentDepth
>= 0;
236 // if (currentDepth == 0)
237 // return "jcr:root";
238 return currentPath
[currentDepth
];
241 protected String
getCurrentJcrPath() {
242 // if (currentDepth == 0)
244 StringBuilder sb
= new StringBuilder(parentPath
.equals("/") ?
"" : parentPath
);
245 for (int i
= 0; i
<= currentDepth
; i
++) {
248 sb
.append(currentPath
[i
]);
250 return sb
.toString();
253 public Set
<String
> getContentPaths() {