View Javadoc
1   package org.argeo.maintenance.backup;
2   
3   import java.io.IOException;
4   import java.io.InputStream;
5   import java.io.Writer;
6   import java.util.Base64;
7   import java.util.Set;
8   import java.util.TreeSet;
9   
10  import javax.jcr.Binary;
11  import javax.jcr.RepositoryException;
12  import javax.jcr.Session;
13  
14  import org.apache.commons.io.IOUtils;
15  import org.xml.sax.Attributes;
16  import org.xml.sax.SAXException;
17  import org.xml.sax.helpers.DefaultHandler;
18  
19  public class BackupContentHandler extends DefaultHandler {
20  	final static int MAX_DEPTH = 1024;
21  	final static String SV_NAMESPACE_URI = "http://www.jcp.org/jcr/sv/1.0";
22  	// elements
23  	final static String NODE = "node";
24  	final static String PROPERTY = "property";
25  	final static String VALUE = "value";
26  	// attributes
27  	final static String NAME = "name";
28  	final static String MULTIPLE = "multiple";
29  	final static String TYPE = "type";
30  
31  	// values
32  	final static String BINARY = "Binary";
33  	final static String JCR_CONTENT = "jcr:content";
34  
35  	private Writer out;
36  	private Session session;
37  	private Set<String> contentPaths = new TreeSet<>();
38  
39  	public BackupContentHandler(Writer out, Session session) {
40  		super();
41  		this.out = out;
42  		this.session = session;
43  	}
44  
45  	private int currentDepth = -1;
46  	private String[] currentPath = new String[MAX_DEPTH];
47  
48  	private boolean currentPropertyIsMultiple = false;
49  	private String currentEncoded = null;
50  	private Base64.Encoder base64encore = Base64.getEncoder();
51  
52  	@Override
53  	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
54  		boolean isNode;
55  		boolean isProperty;
56  		switch (localName) {
57  		case NODE:
58  			isNode = true;
59  			isProperty = false;
60  			break;
61  		case PROPERTY:
62  			isNode = false;
63  			isProperty = true;
64  			break;
65  		default:
66  			isNode = false;
67  			isProperty = false;
68  		}
69  
70  		if (isNode) {
71  			String nodeName = attributes.getValue(SV_NAMESPACE_URI, NAME);
72  			currentDepth = currentDepth + 1;
73  			if (currentDepth > 0)
74  				currentPath[currentDepth - 1] = nodeName;
75  //			System.out.println(getCurrentPath() + " , depth=" + currentDepth);
76  		}
77  
78  		if (SV_NAMESPACE_URI.equals(uri))
79  			try {
80  				out.write("<");
81  				out.write(localName);
82  				if (isProperty)
83  					currentPropertyIsMultiple = false; // always reset
84  				for (int i = 0; i < attributes.getLength(); i++) {
85  					String ns = attributes.getURI(i);
86  					if (SV_NAMESPACE_URI.equals(ns)) {
87  						String attrName = attributes.getLocalName(i);
88  						String attrValue = attributes.getValue(i);
89  						out.write(" ");
90  						out.write(attrName);
91  						out.write("=");
92  						out.write("\"");
93  						out.write(attrValue);
94  						out.write("\"");
95  						if (isProperty) {
96  							if (MULTIPLE.equals(attrName))
97  								currentPropertyIsMultiple = Boolean.parseBoolean(attrValue);
98  							else if (TYPE.equals(attrName)) {
99  								if (BINARY.equals(attrValue)) {
100 									if (JCR_CONTENT.equals(getCurrentName())) {
101 										contentPaths.add(getCurrentPath());
102 									} else {
103 										Binary binary = session.getNode(getCurrentPath()).getProperty(attrName)
104 												.getBinary();
105 										try (InputStream in = binary.getStream()) {
106 											currentEncoded = base64encore.encodeToString(IOUtils.toByteArray(in));
107 										} finally {
108 
109 										}
110 									}
111 								}
112 							}
113 						}
114 					}
115 				}
116 				if (currentDepth == 0) {
117 					out.write(" xmlns=\"" + SV_NAMESPACE_URI + "\"");
118 				}
119 				out.write(">");
120 				if (isNode)
121 					out.write("\n");
122 				else if (isProperty && currentPropertyIsMultiple)
123 					out.write("\n");
124 			} catch (IOException | RepositoryException e) {
125 				// TODO Auto-generated catch block
126 				e.printStackTrace();
127 			}
128 	}
129 
130 	@Override
131 	public void endElement(String uri, String localName, String qName) throws SAXException {
132 		if (localName.equals(NODE)) {
133 //			System.out.println("endElement " + getCurrentPath() + " , depth=" + currentDepth);
134 			if (currentDepth > 0)
135 				currentPath[currentDepth - 1] = null;
136 			currentDepth = currentDepth - 1;
137 		}
138 		boolean isValue = localName.equals(VALUE);
139 		if (SV_NAMESPACE_URI.equals(uri))
140 			try {
141 				if (isValue && currentEncoded != null) {
142 					out.write(currentEncoded);
143 				}
144 				currentEncoded = null;
145 				out.write("</");
146 				out.write(localName);
147 				out.write(">");
148 				if (!isValue)
149 					out.write("\n");
150 				else {
151 					if (currentPropertyIsMultiple)
152 						out.write("\n");
153 				}
154 			} catch (IOException e) {
155 				// TODO Auto-generated catch block
156 				e.printStackTrace();
157 			}
158 	}
159 
160 	@Override
161 	public void characters(char[] ch, int start, int length) throws SAXException {
162 		try {
163 			out.write(ch, start, length);
164 		} catch (IOException e) {
165 			// TODO Auto-generated catch block
166 			e.printStackTrace();
167 		}
168 	}
169 
170 	protected String getCurrentName() {
171 		assert currentDepth >= 0;
172 		if (currentDepth == 0)
173 			return "jcr:root";
174 		return currentPath[currentDepth - 1];
175 	}
176 
177 	protected String getCurrentPath() {
178 		if (currentDepth == 0)
179 			return "/";
180 		StringBuilder sb = new StringBuilder("/");
181 		for (int i = 0; i < currentDepth; i++) {
182 			if (i != 0)
183 				sb.append('/');
184 			sb.append(currentPath[i]);
185 		}
186 		return sb.toString();
187 	}
188 
189 	public Set<String> getContentPaths() {
190 		return contentPaths;
191 	}
192 
193 	
194 	
195 }