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