/
DeploymentOverlayDeploymentUnitProcessor.java
226 lines (200 loc) · 9.98 KB
/
DeploymentOverlayDeploymentUnitProcessor.java
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/
package org.jboss.as.server.deployment;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jboss.as.repository.ContentRepository;
import org.jboss.as.server.deployment.module.ResourceRoot;
import org.jboss.as.server.deployment.module.TempFileProviderService;
import org.jboss.as.server.deploymentoverlay.DeploymentOverlayIndex;
import org.jboss.as.server.logging.ServerLogger;
import org.jboss.vfs.VFS;
import org.jboss.vfs.VirtualFile;
/**
* Deployment unit processor that adds content overrides to the VFS filesystem.
*
* This is a two phase process. First any overlays that can be easily resolved are mounted, however we may not be able
* to mount all overlays because they may depend on VFS mounts that are set up by later structure processors (e.g. if
* there is an overlay for ear/lib/mylib.jar/com/acme/MyClass.class it can't be mounted until the ear structure processor
* has created the mount). These resource roots are identified and deferred to be processed at the end of the structure
* phase.
*
* Note that we can't just process everything at the end, as we may need to replace the archives that are mounted by
* these later processors
*
* @author Stuart Douglas
*/
public class DeploymentOverlayDeploymentUnitProcessor implements DeploymentUnitProcessor {
private final ContentRepository contentRepository;
protected static final AttachmentKey<AttachmentList<Closeable>> MOUNTED_FILES = AttachmentKey.createList(Closeable.class);
protected static final AttachmentKey<Map<String, byte[]>> DEFERRED_OVERLAYS = AttachmentKey.create(Map.class);
public DeploymentOverlayDeploymentUnitProcessor(final ContentRepository contentRepository) {
this.contentRepository = contentRepository;
}
@Override
public void deploy(final DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
final ResourceRoot deploymentRoot = deploymentUnit.getAttachment(Attachments.DEPLOYMENT_ROOT);
Map<String, MountedDeploymentOverlay> mounts = getMountsAttachment(deploymentUnit);
Map<String, byte[]> deferred = getDeferredAttachment(deploymentUnit);
Map<String, byte[]> overlayEntries = getOverlays(deploymentUnit);
if (overlayEntries == null) {
return;
}
//exploded is true if this is a zip deployment that has been mounted exploded
final boolean exploded = MountExplodedMarker.isMountExploded(deploymentUnit) && !ExplodedDeploymentMarker.isExplodedDeployment(deploymentUnit);
final Set<String> paths = new HashSet<String>();
for (final Map.Entry<String, byte[]> entry : overlayEntries.entrySet()) {
String path = entry.getKey();
if (path.startsWith("/")) {
path = path.substring(1);
}
try {
if (!paths.contains(path)) {
VirtualFile mountPoint = deploymentRoot.getRoot().getChild(path);
paths.add(path);
VirtualFile content = contentRepository.getContent(entry.getValue());
if (exploded) {
VirtualFile parent = mountPoint.getParent();
while (!parent.exists()) {
parent = parent.getParent();
}
//we need to check if the parent is a directory
//if it is a file we assume it is an archive that is yet to be mounted and we add it to the deferred list
if(parent.isDirectory()) {
handleExplodedEntryWithDirParent(deploymentUnit, content, mountPoint, mounts, path);
} else {
handleEntryWithFileParent(deferred, entry, path, parent);
}
} else {
VirtualFile parent = mountPoint.getParent();
List<VirtualFile> createParents = new ArrayList<>();
while (!parent.exists()) {
createParents.add(parent);
parent = parent.getParent();
}
//we need to check if the parent is a directory
//if it is a file we assume it is an archive that is yet to be mounted and we add it to the deferred list
if(parent.isDirectory()) {
if (isExplodedSubUnitOverlay(deploymentUnit, mountPoint, path)) {// like: war/*.html
copyFile(content.getPhysicalFile(), mountPoint.getPhysicalFile());
continue;
}
Collections.reverse(createParents);
for (VirtualFile file : createParents) {
Closeable closable = VFS.mountTemp(file, TempFileProviderService.provider());
deploymentUnit.addToAttachmentList(MOUNTED_FILES, closable);
}
Closeable handle = VFS.mountReal(content.getPhysicalFile(), mountPoint);
MountedDeploymentOverlay mounted = new MountedDeploymentOverlay(handle, content.getPhysicalFile(), mountPoint, TempFileProviderService.provider());
deploymentUnit.addToAttachmentList(MOUNTED_FILES, mounted);
mounts.put(path, mounted);
} else {
//we have an overlay that is targeted at a file, most likely a zip file that is yet to be mounted by a structure processor
//we take note of these overlays and try and mount them at the end of the STRUCTURE phase
handleEntryWithFileParent(deferred, entry, path, parent);
}
}
}
} catch (IOException e) {
throw ServerLogger.ROOT_LOGGER.deploymentOverlayFailed(e, entry.getKey(), path);
}
}
}
private boolean isExplodedSubUnitOverlay(DeploymentUnit deploymentUnit, VirtualFile mountPoint, String path) {
final List<ResourceRoot> childRes = deploymentUnit.getAttachmentList(Attachments.RESOURCE_ROOTS);
if (childRes != null) {
for (ResourceRoot rs: childRes) {
if (path.startsWith(rs.getRoot().getName())) {
String relativePath = mountPoint.getPathNameRelativeTo(rs.getRoot());
if (relativePath != null
&& relativePath.length() > 0
&& SubExplodedDeploymentMarker.isSubExplodedResourceRoot(rs)) {
return true;
}
}
}
}
return false;
}
protected void handleEntryWithFileParent(Map<String, byte[]> deferred, Map.Entry<String, byte[]> entry, String path, VirtualFile parent) {
deferred.put(path, entry.getValue());
}
protected void handleExplodedEntryWithDirParent(DeploymentUnit deploymentUnit,
VirtualFile content, VirtualFile mountPoint, Map<String, MountedDeploymentOverlay> mounts,
String overLayPath) throws IOException{
copyFile(content.getPhysicalFile(), mountPoint.getPhysicalFile());
}
protected Map<String, byte[]> getDeferredAttachment(DeploymentUnit deploymentUnit) {
Map<String, byte[]> deferred = new HashMap<>();
deploymentUnit.putAttachment(DEFERRED_OVERLAYS, deferred);
return deferred;
}
protected Map<String, MountedDeploymentOverlay> getMountsAttachment(DeploymentUnit deploymentUnit) {
Map<String, MountedDeploymentOverlay> mounts = new HashMap<String, MountedDeploymentOverlay>();
deploymentUnit.putAttachment(Attachments.DEPLOYMENT_OVERLAY_LOCATIONS, mounts);
return mounts;
}
protected Map<String, byte[]> getOverlays(DeploymentUnit deploymentUnit) {
DeploymentOverlayIndex overlays = deploymentUnit.getAttachment(Attachments.DEPLOYMENT_OVERLAY_INDEX);
if(overlays == null) {
return null;
}
Map<String, byte[]> overlayEntries = overlays.getOverlays(deploymentUnit.getName());
return overlayEntries;
}
@Override
public void undeploy(final DeploymentUnit context) {
for (Closeable closable : context.getAttachmentList(MOUNTED_FILES)) {
try {
closable.close();
} catch (IOException e) {
ServerLogger.DEPLOYMENT_LOGGER.failedToUnmountContentOverride(e);
}
}
}
protected static void copyFile(final File src, final File dest) throws IOException {
final InputStream in = new BufferedInputStream(new FileInputStream(src));
try {
copyFile(in, dest);
} finally {
close(in);
}
}
protected static void copyFile(final InputStream in, final File dest) throws IOException {
dest.getParentFile().mkdirs();
byte[] buff = new byte[1024];
final OutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
try {
int i = in.read(buff);
while (i > 0) {
out.write(buff, 0, i);
i = in.read(buff);
}
} finally {
close(out);
}
}
protected static void close(Closeable closeable) {
try {
closeable.close();
} catch (IOException ignore) {
}
}
}