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.module.files;
35
36 import info.magnolia.cms.core.Content;
37 import info.magnolia.cms.core.HierarchyManager;
38 import info.magnolia.cms.util.ContentUtil;
39 import info.magnolia.jcr.util.NodeTypes;
40 import info.magnolia.jcr.util.NodeUtil;
41 import info.magnolia.jcr.util.PropertyUtil;
42
43 import java.io.File;
44 import java.io.FileInputStream;
45 import java.io.IOException;
46 import java.io.InputStream;
47 import java.io.OutputStream;
48 import java.security.DigestInputStream;
49 import java.security.DigestOutputStream;
50 import java.security.MessageDigest;
51 import java.security.NoSuchAlgorithmException;
52
53 import javax.jcr.Node;
54 import javax.jcr.RepositoryException;
55 import javax.jcr.Session;
56
57 import org.apache.commons.codec.binary.Hex;
58 import org.apache.commons.io.IOUtils;
59 import org.apache.commons.lang3.StringUtils;
60
61
62
63
64
65
66
67
68
69
70
71 class MD5CheckingFileExtractorOperation extends BasicFileExtractorOperation {
72 private final FileExtractionLogger log;
73 private final Session session;
74
75
76
77
78 @Deprecated
79 MD5CheckingFileExtractorOperation(FileExtractionLogger log, HierarchyManager hm, String resourcePath, String absoluteTargetPath) {
80 super(resourcePath, absoluteTargetPath);
81 this.log = log;
82 this.session = hm.getWorkspace().getSession();
83 }
84
85 MD5CheckingFileExtractorOperation(FileExtractionLogger log, Session session, String resourcePath, String absoluteTargetPath) {
86 super(resourcePath, absoluteTargetPath);
87 this.log = log;
88 this.session = session;
89 }
90
91 @Override
92 protected InputStream checkInput() throws IOException {
93 return wrap(super.checkInput());
94 }
95
96
97 @Override
98 protected File checkOutput() throws IOException {
99 final File out = super.checkOutput();
100
101 if (out.exists()) {
102
103 final InputStream stream = new FileInputStream(out);
104 try {
105 final String existingFileMD5 = calculateMD5(stream);
106 final String repoMD5 = PropertyUtil.getString(getOrCreateNode(), "md5");
107
108
109 if (StringUtils.isNotBlank(repoMD5)) {
110 if (existingFileMD5.equals(repoMD5)) {
111
112 return out;
113 }
114 log.error("Can't extract " + resourcePath + " as this file was probably modified locally: expected MD5 [" + repoMD5 + "] but current MD5 is [" + existingFileMD5 + "].");
115 return null;
116 }
117 } finally {
118 IOUtils.closeQuietly(stream);
119 }
120
121 } else {
122
123 }
124 return out;
125 }
126
127 @Override
128 protected OutputStream openOutput(File outFile) throws IOException {
129 final OutputStream outputStream = super.openOutput(outFile);
130 final MessageDigest md5 = getMessageDigest();
131 return new DigestOutputStream(outputStream, md5);
132 }
133
134 @Override
135 protected void copyAndClose(InputStream in, OutputStream out) throws IOException {
136 super.copyAndClose(in, out);
137
138 final DigestInputStream md5Stream = (DigestInputStream) in;
139 final String newMD5 = retrieveMD5(md5Stream);
140
141 try {
142 getOrCreateNode().setProperty("md5", newMD5);
143 } catch (RepositoryException e) {
144 throw new RuntimeException(e);
145 }
146
147 }
148
149 protected Node getOrCreateNode() {
150 try {
151 final String repoPath = getRepositoryPath(resourcePath);
152 final Node node;
153 if (!session.nodeExists(repoPath)) {
154 node = NodeUtil.createPath(session.getRootNode(), repoPath, NodeTypes.Content.NAME);
155 } else {
156 node = session.getNode(repoPath);
157 }
158 return node;
159 } catch (RepositoryException e) {
160 throw new RuntimeException(e);
161 }
162 }
163
164
165
166
167 @Deprecated
168 protected Content getRepositoryNode() {
169 return ContentUtil.asContent(getOrCreateNode());
170 }
171
172
173
174
175
176 protected String getRepositoryPath(String resourcePath) {
177 return "/server/install" + resourcePath;
178 }
179
180
181
182
183
184 protected String calculateMD5(InputStream stream) throws IOException {
185 final DigestInputStream md5Stream = wrap(stream);
186 byte[] buffer = new byte[1024];
187 while (md5Stream.read(buffer) != -1) {
188 }
189
190 return retrieveMD5(md5Stream);
191 }
192
193 protected DigestInputStream wrap(InputStream stream) {
194 final MessageDigest md5 = getMessageDigest();
195 return new DigestInputStream(stream, md5);
196 }
197
198 protected String retrieveMD5(DigestInputStream md5Stream) {
199 final byte[] digInBytes = md5Stream.getMessageDigest().digest();
200 return String.valueOf(Hex.encodeHex(digInBytes));
201 }
202
203 protected MessageDigest getMessageDigest() {
204 try {
205 return MessageDigest.getInstance("MD5");
206 } catch (NoSuchAlgorithmException e) {
207 throw new RuntimeException("Can't check files with md5: " + e.getMessage(), e);
208 }
209 }
210 }