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.contenthandler.XmlContentHandlerFactory;
39 import info.magnolia.importexport.contenthandler.YamlContentHandler;
40 import info.magnolia.importexport.exporter.YamlExporter;
41 import info.magnolia.importexport.filters.NamespaceFilter;
42 import info.magnolia.jcr.decoration.ContentDecorator;
43 import info.magnolia.jcr.decoration.NodePredicateContentDecorator;
44 import info.magnolia.jcr.predicate.AbstractPredicate;
45 import info.magnolia.jcr.predicate.NodeFilteringPredicate;
46 import info.magnolia.jcr.predicate.PropertyFilteringPredicate;
47 import info.magnolia.objectfactory.Classes;
48
49 import java.io.OutputStream;
50 import java.util.Arrays;
51 import java.util.HashMap;
52 import java.util.Map;
53 import java.util.zip.DeflaterOutputStream;
54 import java.util.zip.GZIPOutputStream;
55 import java.util.zip.ZipEntry;
56 import java.util.zip.ZipOutputStream;
57
58 import javax.jcr.Node;
59 import javax.jcr.Property;
60 import javax.jcr.Session;
61
62 import org.apache.commons.io.IOUtils;
63 import org.apache.commons.lang3.StringUtils;
64 import org.apache.jackrabbit.JcrConstants;
65 import org.apache.jackrabbit.commons.xml.Exporter;
66 import org.apache.jackrabbit.commons.xml.SystemViewExporter;
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 boolean prettyPrint = true;
82
83 @Override
84 public boolean execute(Context context) throws Exception {
85 String pathName = DataTransporter.createExportPath(getPath());
86 pathName = DataTransporter.encodePath(pathName, DataTransporter.DOT, DataTransporter.UTF8);
87 if (DataTransporter.DOT.equals(pathName)) {
88 pathName = StringUtils.EMPTY;
89 }
90 OutputStream compressionOutputStream = getOutputStream();
91 String format = getFormat();
92 final String fileName = getRepository() + pathName;
93
94 switch (compression) {
95 case ZIP:
96 final ZipOutputStream zipOutputStream = new ZipOutputStream(compressionOutputStream);
97 zipOutputStream.putNextEntry(new ZipEntry(fileName + "." + format));
98 compressionOutputStream = zipOutputStream;
99 format = getCompression();
100 break;
101 case GZ:
102 format += "." + getCompression();
103 compressionOutputStream = new GZIPOutputStream(compressionOutputStream);
104 break;
105 }
106 setFileName(fileName + "." + format);
107
108 try {
109 final Session session = context.getJCRSession(getRepository());
110 final ContentHandler contentHandler = this.format.getContentHandler(compressionOutputStream, isPrettyPrint());
111
112 final Exporter exporter = Classes.getClassFactory().newInstance(getExporterClass(), session, contentHandler, true, true);
113 final ContentDecorator contentDecorator = filters.containsKey(getRepository()) ? filters.get(getRepository()) : new DefaultFilter();
114 final Node node = contentDecorator.wrapNode(getJCRNode(context));
115
116 exporter.export(node);
117 } finally {
118
119 if (compressionOutputStream instanceof DeflaterOutputStream) {
120 ((DeflaterOutputStream) compressionOutputStream).finish();
121 }
122 compressionOutputStream.flush();
123 IOUtils.closeQuietly(compressionOutputStream);
124 }
125 return true;
126 }
127
128 public OutputStream getOutputStream() {
129 return outputStream;
130 }
131
132 public void setOutputStream(OutputStream outputStream) {
133 this.outputStream = outputStream;
134 }
135
136 public String getFormat() {
137 return format.name().toLowerCase();
138 }
139
140 public void setFormat(String format) {
141 this.format = Format.valueOf(format.toUpperCase());
142 }
143
144 public String getCompression() {
145 return compression.name().toLowerCase();
146 }
147
148 public void setCompression(String compression) {
149 this.compression = Compression.valueOf(compression.toUpperCase());
150 }
151
152 public Map<String, ContentDecorator> getFilters() {
153 return filters;
154 }
155
156 public void setFilters(Map<String, ContentDecorator> filters) {
157 this.filters = filters;
158 }
159
160 public Class<? extends Exporter> getExporterClass() {
161 return exporterClass == null ? format.getDefaultExporterClass() : exporterClass;
162 }
163
164 public void setExporterClass(Class<? extends Exporter> exporterClass) {
165 this.exporterClass = exporterClass;
166 }
167
168 public boolean isPrettyPrint() {
169 return prettyPrint;
170 }
171
172 public void setPrettyPrint(boolean prettyPrint) {
173 this.prettyPrint = prettyPrint;
174 }
175
176
177
178
179 public static class DefaultFilter extends NodePredicateContentDecorator {
180
181 public DefaultFilter() {
182 final NodeFilteringPredicatehtml#NodeFilteringPredicate">NodeFilteringPredicate nodePredicate = new NodeFilteringPredicate();
183 nodePredicate.setNodeTypes(Lists.newArrayList("rep:AccessControl", "rep:root", "rep:system"));
184 final PropertyFilteringPredicate#PropertyFilteringPredicate">PropertyFilteringPredicate propertyPredicate = new PropertyFilteringPredicate();
185 propertyPredicate.setExcludedNames(Lists.newArrayList("jcr:createdBy", JcrConstants.JCR_CREATED));
186 setPropertyPredicate(propertyPredicate);
187 setNodePredicate(nodePredicate);
188 }
189
190 @Override
191 public PropertyFilteringPredicate getPropertyPredicate() {
192 return (PropertyFilteringPredicate) super.getPropertyPredicate();
193 }
194
195 @Override
196 public void setPropertyPredicate(AbstractPredicate<Property> propertyPredicate) {
197 if (propertyPredicate instanceof PropertyFilteringPredicate) {
198 super.setPropertyPredicate(propertyPredicate);
199 } else {
200 throw new IllegalArgumentException(String.format("Expected instances of {%s} but got {%s}", PropertyFilteringPredicate.class, propertyPredicate.getClass()));
201 }
202 }
203
204 @Override
205 public NodeFilteringPredicate getNodePredicate() {
206 return (NodeFilteringPredicate) super.getNodePredicate();
207 }
208
209 @Override
210 public void setNodePredicate(AbstractPredicate<Node> propertyPredicate) {
211 if (propertyPredicate instanceof NodeFilteringPredicate) {
212 super.setNodePredicate(propertyPredicate);
213 } else {
214 throw new IllegalArgumentException(String.format("Expected instances of {%s} but got {%s}", PropertyFilteringPredicate.class, propertyPredicate.getClass()));
215 }
216 }
217 }
218
219
220
221
222
223 public enum Format {
224 XML(SystemViewExporter.class) {
225 @Override
226 public ContentHandler getContentHandler(OutputStream out, boolean prettyPrint) {
227
228 NamespaceFiltermespaceFilter.html#NamespaceFilter">NamespaceFilter filter = new NamespaceFilter("sv", "xsi");
229 filter.setContentHandler(XmlContentHandlerFactory.newXmlContentHandler(out, prettyPrint));
230 return filter;
231 }
232 },
233
234 YAML(YamlExporter.class) {
235 @Override
236 public ContentHandler getContentHandler(OutputStream out, boolean prettyPrint) {
237
238 NamespaceFiltermespaceFilter.html#NamespaceFilter">NamespaceFilter filter = new NamespaceFilter();
239 filter.setContentHandler(new YamlContentHandler(out));
240 return filter;
241 }
242 };
243
244 private final Class<? extends Exporter> defaultExporter;
245
246 Format(Class<? extends Exporter> defaultExporter) {
247 this.defaultExporter = defaultExporter;
248 }
249
250 public Class<? extends Exporter> getDefaultExporterClass() {
251 return defaultExporter;
252 }
253
254 protected ContentHandler getContentHandler(OutputStream out) {
255 return getContentHandler(out, true);
256 }
257
258 protected abstract ContentHandler getContentHandler(OutputStream out, boolean prettyPrint);
259
260 public static boolean isSupportedExtension(String extension) {
261 return Arrays.stream(values()).anyMatch(f -> StringUtils.equals(f.name(), StringUtils.upperCase(extension)));
262 }
263 }
264
265
266
267
268 public enum Compression {
269 NONE,
270 ZIP,
271 GZ
272 }
273 }