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