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.ui.framework.command;
35
36 import info.magnolia.cms.beans.config.MIMEMapping;
37 import info.magnolia.cms.core.FileSystemHelper;
38 import info.magnolia.cms.core.Path;
39 import info.magnolia.commands.impl.BaseRepositoryCommand;
40 import info.magnolia.context.Context;
41 import info.magnolia.i18nsystem.SimpleTranslator;
42 import info.magnolia.jcr.util.NodeTypes;
43 import info.magnolia.jcr.util.NodeUtil;
44 import info.magnolia.objectfactory.Components;
45 import info.magnolia.ui.form.field.upload.UploadReceiver;
46
47 import java.io.File;
48 import java.io.FileOutputStream;
49 import java.io.IOException;
50 import java.io.InputStream;
51 import java.util.Collections;
52 import java.util.Comparator;
53 import java.util.Iterator;
54 import java.util.List;
55
56 import javax.inject.Inject;
57 import javax.jcr.Node;
58 import javax.jcr.RepositoryException;
59
60 import org.apache.commons.collections4.EnumerationUtils;
61 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
62 import org.apache.commons.compress.archivers.zip.ZipFile;
63 import org.apache.commons.io.IOUtils;
64 import org.apache.commons.lang3.StringUtils;
65 import org.vaadin.easyuploads.UploadField;
66
67
68
69
70 public class ImportZipCommand extends BaseRepositoryCommand {
71
72 public static final String STREAM_PROPERTY = "inputStream";
73
74 public static final String ENCODING_PROPERTY = "encoding";
75
76 public static final String ZIP_TMP_FILE_PREFIX = "zipupload";
77
78 public static final String ZIP_TMP_FILE_SUFFIX = ".zip";
79
80 public static final String DEFAULT_MIME_TYPE = "application/octet-stream";
81
82 public static final String BACKSLASH_DUMMY = "________backslash________";
83
84 private final SimpleTranslator i18n;
85 private final FileSystemHelper fileSystemHelper;
86
87 private InputStream inputStream;
88
89 protected Context context;
90
91 private String encoding;
92
93 @Inject
94 public ImportZipCommand(SimpleTranslator i18n, FileSystemHelper fileSystemHelper) {
95 this.i18n = i18n;
96 this.fileSystemHelper = fileSystemHelper;
97 }
98
99
100
101
102 @Deprecated
103 public ImportZipCommand(SimpleTranslator i18n) {
104 this(i18n, Components.getComponent(FileSystemHelper.class));
105 }
106
107 @Override
108 public boolean execute(Context context) throws Exception {
109 this.context = context;
110 File tmpFile = null;
111 FileOutputStream tmpStream = null;
112 File tempDirectory = fileSystemHelper.getTempDirectory();
113 try {
114 tmpFile = File.createTempFile(ZIP_TMP_FILE_PREFIX, ZIP_TMP_FILE_SUFFIX, tempDirectory);
115 tmpStream = new FileOutputStream(tmpFile);
116 IOUtils.copy(inputStream, tmpStream);
117 } catch (IOException e) {
118 log.error("Failed to dump zip file to temp file: ", e);
119 throw e;
120 } finally {
121 IOUtils.closeQuietly(tmpStream);
122 IOUtils.closeQuietly(inputStream);
123 }
124
125 if (isValid(tmpFile)) {
126 ZipFile zip = new ZipFile(tmpFile, getEncoding());
127
128
129
130
131 final List zipEntries = EnumerationUtils.toList(zip.getEntries());
132 Collections.sort(zipEntries, new Comparator() {
133 @Override
134 public int compare(Object first, Object second) {
135 ZipArchiveEntry firstEntry = ((ZipArchiveEntry) first);
136 ZipArchiveEntry secondEntry = ((ZipArchiveEntry) second);
137 if (firstEntry.isDirectory() != secondEntry.isDirectory()) {
138
139 return Boolean.compare(secondEntry.isDirectory(), firstEntry.isDirectory());
140 }
141
142 return firstEntry.getName().compareTo(secondEntry.getName());
143 }
144 });
145
146 final Iterator it = zipEntries.iterator();
147 while (it.hasNext()) {
148 ZipArchiveEntry entry = (ZipArchiveEntry) it.next();
149 processEntry(zip, entry);
150 }
151 context.getJCRSession(getRepository()).save();
152 }
153 return false;
154 }
155
156 private void processEntry(ZipFile zip, ZipArchiveEntry entry) throws IOException, RepositoryException {
157 if (entry.getName().startsWith("__MACOSX")) {
158 return;
159 } else if (entry.getName().endsWith(".DS_Store")) {
160 return;
161 }
162
163 if (entry.isDirectory()) {
164 ensureFolder(entry);
165 } else {
166 handleFileEntry(zip, entry);
167 }
168
169 }
170
171 protected void handleFileEntry(ZipFile zip, ZipArchiveEntry entry) throws IOException, RepositoryException {
172 String fileName = entry.getName();
173 if (StringUtils.contains(fileName, "/")) {
174 fileName = StringUtils.substringAfterLast(fileName, "/");
175 }
176
177 String extension = StringUtils.substringAfterLast(fileName, ".");
178 InputStream stream = zip.getInputStream(entry);
179 FileOutputStream os = null;
180 try {
181 UploadReceiver receiver = createReceiver();
182
183 String folderPath = extractEntryPath(entry);
184 if (folderPath.startsWith("/")) {
185 folderPath = folderPath.substring(1);
186 }
187 Node folder = getJCRNode(context);
188 if (StringUtils.isNotBlank(folderPath)) {
189 if (folder.hasNode(folderPath)) {
190 folder = folder.getNode(folderPath);
191 } else {
192 folder = NodeUtil.createPath(folder, folderPath, NodeTypes.Folder.NAME, true);
193 }
194 }
195 receiver.setFieldType(UploadField.FieldType.BYTE_ARRAY);
196 receiver.receiveUpload(fileName, StringUtils.defaultIfEmpty(MIMEMapping.getMIMEType(extension), DEFAULT_MIME_TYPE));
197 receiver.setValue(IOUtils.toByteArray(stream));
198
199 doHandleEntryFromReceiver(folder, receiver);
200 } catch (Exception e) {
201 throw e;
202 } finally {
203 IOUtils.closeQuietly(stream);
204 IOUtils.closeQuietly(os);
205 }
206 }
207
208 protected UploadReceiver createReceiver() {
209 return new UploadReceiver(Path.getTempDirectory(), i18n);
210 }
211
212
213
214
215
216
217
218
219 protected void doHandleEntryFromReceiver(Node folder, UploadReceiver receiver) throws RepositoryException {
220 }
221
222 private void ensureFolder(ZipArchiveEntry entry) throws RepositoryException {
223 String path = extractEntryPath(entry);
224 NodeUtil.createPath(getJCRNode(context), path, NodeTypes.Folder.NAME, true);
225 }
226
227 private String extractEntryPath(ZipArchiveEntry entry) {
228 String entryName = entry.getName();
229 String path = (StringUtils.contains(entryName, "/")) ? StringUtils.substringBeforeLast(entryName, "/") : "/";
230
231 if (!path.startsWith("/")) {
232 path = "/" + path;
233 }
234
235
236 path = StringUtils.replace(path, "/", BACKSLASH_DUMMY);
237 path = Path.getValidatedLabel(path);
238 path = StringUtils.replace(path, BACKSLASH_DUMMY, "/");
239 return path;
240 }
241
242 private boolean isValid(File tmpFile) {
243 return tmpFile != null;
244 }
245
246
247 public InputStream getInputStream() {
248 return inputStream;
249 }
250
251 public void setInputStream(InputStream inputStream) {
252 this.inputStream = inputStream;
253 }
254
255 public String getEncoding() {
256 return encoding;
257 }
258
259 public void setEncoding(String encoding) {
260 this.encoding = encoding;
261 }
262 }