1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.importexport.command;
35
36 import info.magnolia.context.Context;
37 import info.magnolia.importexport.DataTransporter;
38 import info.magnolia.importexport.exporter.YamlExporter;
39 import info.magnolia.importexport.outputter.YamlOutputter;
40 import info.magnolia.jcr.decoration.ContentDecorator;
41 import info.magnolia.jcr.decoration.NodePredicateContentDecorator;
42 import info.magnolia.jcr.predicate.AbstractPredicate;
43 import info.magnolia.jcr.predicate.NodeFilteringPredicate;
44 import info.magnolia.jcr.predicate.PropertyFilteringPredicate;
45 import info.magnolia.objectfactory.Classes;
46
47 import java.io.OutputStream;
48 import java.util.Arrays;
49 import java.util.HashMap;
50 import java.util.Map;
51 import java.util.zip.DeflaterOutputStream;
52 import java.util.zip.GZIPOutputStream;
53 import java.util.zip.ZipEntry;
54 import java.util.zip.ZipOutputStream;
55
56 import javax.jcr.Node;
57 import javax.jcr.Property;
58 import javax.jcr.Session;
59
60 import org.apache.commons.io.IOUtils;
61 import org.apache.commons.lang3.StringUtils;
62 import org.apache.jackrabbit.JcrConstants;
63 import org.apache.jackrabbit.commons.xml.Exporter;
64 import org.apache.jackrabbit.commons.xml.SystemViewExporter;
65 import org.jdom.output.XMLOutputter;
66 import org.jdom.transform.JDOMResult;
67 import org.xml.sax.ContentHandler;
68
69 import com.google.common.collect.Lists;
70
71
72
73
74 public class JcrExportCommand extends JcrImportCommand {
75
76 private OutputStream outputStream;
77 private Format format = Format.XML;
78 private Compression compression = Compression.NONE;
79 private Map<String, ContentDecorator> filters = new HashMap<>();
80 private Class<? extends Exporter> exporterClass;
81 private XMLOutputter outputter;
82
83 public JcrExportCommand() {
84 final org.jdom.output.Format format = org.jdom.output.Format.getPrettyFormat();
85 format.setTextMode(org.jdom.output.Format.TextMode.PRESERVE);
86 format.setLineSeparator("\n");
87 getOutputter().setFormat(format);
88 }
89
90 @Override
91 public boolean execute(Context context) throws Exception {
92 String pathName = DataTransporter.createExportPath(getPath());
93 pathName = DataTransporter.encodePath(pathName, DataTransporter.DOT, DataTransporter.UTF8);
94 if (DataTransporter.DOT.equals(pathName)) {
95 pathName = StringUtils.EMPTY;
96 }
97 OutputStream compressionOutputStream = getOutputStream();
98 String format = getFormat();
99 final String fileName = getRepository() + pathName;
100
101 switch (compression) {
102 case ZIP:
103 final ZipOutputStream zipOutputStream = new ZipOutputStream(compressionOutputStream);
104 zipOutputStream.putNextEntry(new ZipEntry(fileName + "." + format));
105 compressionOutputStream = zipOutputStream;
106 format = getCompression();
107 break;
108 case GZ:
109 format += "." + getCompression();
110 compressionOutputStream = new GZIPOutputStream(compressionOutputStream);
111 break;
112 }
113 setFileName(fileName + "." + format);
114
115 try {
116 final Session session = context.getJCRSession(getRepository());
117 final JDOMResult jdomResult = new JDOMResult();
118 final ContentHandler contentHandler = jdomResult.getHandler();
119 final Exporter exporter = Classes.getClassFactory().newInstance(getExporterClass(), session, contentHandler, true, true);
120 final XMLOutputter xmlOutputter = getOutputter();
121 final ContentDecorator contentDecorator = filters.containsKey(getRepository()) ? filters.get(getRepository()) : new DefaultFilter();
122 final Node node = contentDecorator.wrapNode(getJCRNode(context));
123
124 exporter.export(node);
125 try {
126 xmlOutputter.output(jdomResult.getDocument(), compressionOutputStream);
127 } catch (IllegalStateException e) {
128 xmlOutputter.output(jdomResult.getResult(), compressionOutputStream);
129 }
130 } finally {
131
132 if (compressionOutputStream instanceof DeflaterOutputStream) {
133 ((DeflaterOutputStream) compressionOutputStream).finish();
134 }
135 compressionOutputStream.flush();
136 IOUtils.closeQuietly(compressionOutputStream);
137 }
138 return true;
139 }
140
141 public OutputStream getOutputStream() {
142 return outputStream;
143 }
144
145 public void setOutputStream(OutputStream outputStream) {
146 this.outputStream = outputStream;
147 }
148
149 public String getFormat() {
150 return format.name().toLowerCase();
151 }
152
153 public void setFormat(String format) {
154 this.format = Format.valueOf(format.toUpperCase());
155 }
156
157 public String getCompression() {
158 return compression.name().toLowerCase();
159 }
160
161 public void setCompression(String compression) {
162 this.compression = Compression.valueOf(compression.toUpperCase());
163 }
164
165 public XMLOutputter getOutputter() {
166 return outputter == null ? format.getDefaultOutputter() : outputter;
167 }
168
169 public void setOutputter(XMLOutputter outputter) {
170 this.outputter = outputter;
171 }
172
173 public Map<String, ContentDecorator> getFilters() {
174 return filters;
175 }
176
177 public void setFilters(Map<String, ContentDecorator> filters) {
178 this.filters = filters;
179 }
180
181 public Class<? extends Exporter> getExporterClass() {
182 return exporterClass == null ? format.getDefaultExporterClass() : exporterClass;
183 }
184
185 public void setExporterClass(Class<? extends Exporter> exporterClass) {
186 this.exporterClass = exporterClass;
187 }
188
189
190
191
192 public static class DefaultFilter extends NodePredicateContentDecorator {
193
194 public DefaultFilter() {
195 final NodeFilteringPredicate nodePredicate = new NodeFilteringPredicate();
196 nodePredicate.setNodeTypes(Lists.newArrayList("rep:AccessControl", "rep:root", "rep:system"));
197 final PropertyFilteringPredicate propertyPredicate = new PropertyFilteringPredicate();
198 propertyPredicate.setExcludedNames(Lists.newArrayList("jcr:createdBy", JcrConstants.JCR_CREATED));
199 setPropertyPredicate(propertyPredicate);
200 setNodePredicate(nodePredicate);
201 }
202
203 @Override
204 public PropertyFilteringPredicate getPropertyPredicate() {
205 return (PropertyFilteringPredicate) super.getPropertyPredicate();
206 }
207
208 @Override
209 public void setPropertyPredicate(AbstractPredicate<Property> propertyPredicate) {
210 if (propertyPredicate instanceof PropertyFilteringPredicate) {
211 super.setPropertyPredicate(propertyPredicate);
212 } else {
213 throw new IllegalArgumentException(String.format("Expected instances of {%s} but got {%s}", PropertyFilteringPredicate.class, propertyPredicate.getClass()));
214 }
215 }
216
217 @Override
218 public NodeFilteringPredicate getNodePredicate() {
219 return (NodeFilteringPredicate) super.getNodePredicate();
220 }
221
222 @Override
223 public void setNodePredicate(AbstractPredicate<Node> propertyPredicate) {
224 if (propertyPredicate instanceof NodeFilteringPredicate) {
225 super.setNodePredicate(propertyPredicate);
226 } else {
227 throw new IllegalArgumentException(String.format("Expected instances of {%s} but got {%s}", PropertyFilteringPredicate.class, propertyPredicate.getClass()));
228 }
229 }
230 }
231
232
233
234
235
236 public enum Format {
237
238 XML(SystemViewExporter.class, new XMLOutputter()),
239 YAML(YamlExporter.class, new YamlOutputter());
240
241 private final Class<? extends Exporter> defaultExporter;
242 private final XMLOutputter defaultOutputter;
243
244 Format(Class<? extends Exporter> defaultExporter, XMLOutputter defaultOutputter) {
245 this.defaultExporter = defaultExporter;
246 this.defaultOutputter = defaultOutputter;
247 }
248
249 public Class<? extends Exporter> getDefaultExporterClass() {
250 return defaultExporter;
251 }
252
253 public XMLOutputter getDefaultOutputter() {
254 return defaultOutputter;
255 }
256
257 public static boolean isSupportedExtension(String extension) {
258 return Arrays.stream(values()).anyMatch(f -> StringUtils.equals(f.name(), StringUtils.upperCase(extension)));
259 }
260 }
261
262
263
264
265 public enum Compression {
266 NONE,
267 ZIP,
268 GZ
269 }
270 }