1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package io.wcm.tooling.commons.packmgr.install.crx;
21
22 import static io.wcm.tooling.commons.packmgr.PackageManagerHelper.CRX_PACKAGE_EXISTS_ERROR_MESSAGE_PREFIX;
23
24 import java.io.IOException;
25 import java.net.URISyntaxException;
26 import java.util.Map;
27
28 import org.apache.commons.lang3.StringUtils;
29 import org.apache.http.client.methods.HttpGet;
30 import org.apache.http.client.methods.HttpPost;
31 import org.apache.http.client.protocol.HttpClientContext;
32 import org.apache.http.client.utils.URIBuilder;
33 import org.apache.http.entity.mime.MultipartEntityBuilder;
34 import org.apache.http.impl.client.CloseableHttpClient;
35 import org.apache.jackrabbit.vault.packaging.PackageProperties;
36 import org.json.JSONObject;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 import io.wcm.tooling.commons.packmgr.PackageManagerException;
41 import io.wcm.tooling.commons.packmgr.PackageManagerHelper;
42 import io.wcm.tooling.commons.packmgr.PackageManagerProperties;
43 import io.wcm.tooling.commons.packmgr.install.PackageFile;
44 import io.wcm.tooling.commons.packmgr.install.VendorInstallerFactory;
45 import io.wcm.tooling.commons.packmgr.install.VendorPackageInstaller;
46 import io.wcm.tooling.commons.packmgr.util.ContentPackageProperties;
47 import io.wcm.tooling.commons.packmgr.util.HttpClientUtil;
48
49
50
51
52 public class CrxPackageInstaller implements VendorPackageInstaller {
53
54 private final String url;
55
56 private static final Logger log = LoggerFactory.getLogger(CrxPackageInstaller.class);
57
58
59
60
61 public CrxPackageInstaller(String url) {
62 this.url = url;
63 }
64
65 @Override
66 public void installPackage(PackageFile packageFile, boolean replicate, PackageManagerHelper pkgmgr,
67 CloseableHttpClient httpClient, HttpClientContext packageManagerHttpClientContext, HttpClientContext consoleHttpClientContext,
68 PackageManagerProperties props) throws IOException, PackageManagerException {
69
70 boolean force = packageFile.isForce();
71
72 if (force) {
73
74 ensurePackageManagerAvailability(pkgmgr, httpClient, packageManagerHttpClientContext);
75 }
76 else {
77
78
79 PackageInstalledStatus status = getPackageInstalledStatus(packageFile, pkgmgr, httpClient, packageManagerHttpClientContext);
80 switch (status) {
81 case NOT_FOUND:
82 log.debug("Package is not found in package list: proceed with install.");
83 break;
84 case INSTALLED:
85 log.info("Package skipped because it was already uploaded.");
86 return;
87 case UPLOADED:
88 log.info("Package was already uploaded but not installed: proceed with install and switch to force mode.");
89 force = true;
90 break;
91 case INSTALLED_OTHER_VERSION:
92 log.info("Package was already uploaded, but another version was installed more recently: proceed with install and switch to force mode.");
93 force = true;
94 break;
95 default:
96 throw new PackageManagerException("Unexpected status: " + status);
97 }
98 }
99
100
101 HttpPost post = new HttpPost(url + "/.json?cmd=upload");
102 HttpClientUtil.applyRequestConfig(post, packageFile, props);
103 MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create()
104 .addBinaryBody("package", packageFile.getFile());
105 if (force) {
106 entityBuilder.addTextBody("force", "true");
107 }
108 post.setEntity(entityBuilder.build());
109
110
111 JSONObject jsonResponse = pkgmgr.executePackageManagerMethodJson(httpClient, packageManagerHttpClientContext, post);
112 boolean success = jsonResponse.optBoolean("success", false);
113 String msg = jsonResponse.optString("msg", null);
114 String path = jsonResponse.optString("path", null);
115 if (success) {
116 if (packageFile.isInstall()) {
117 log.info("Package uploaded to {}, now installing...", path);
118
119 try {
120 post = new HttpPost(url + "/console.html" + new URIBuilder().setPath(path).build().getRawPath() + "?cmd=install"
121 + (packageFile.isRecursive() ? "&recursive=true" : ""));
122 HttpClientUtil.applyRequestConfig(post, packageFile, props);
123 }
124 catch (URISyntaxException ex) {
125 throw new PackageManagerException("Invalid path: " + path, ex);
126 }
127
128
129 pkgmgr.executePackageManagerMethodHtmlOutputResponse(httpClient, packageManagerHttpClientContext, post);
130
131
132 delay(packageFile.getDelayAfterInstallSec());
133
134
135 pkgmgr.waitForBundlesActivation(httpClient, consoleHttpClientContext);
136
137 pkgmgr.waitForPackageManagerInstallStatusFinished(httpClient, packageManagerHttpClientContext);
138 }
139 else {
140 log.info("Package uploaded successfully to {} (without installing).", path);
141 }
142 }
143 else if (StringUtils.startsWith(msg, CRX_PACKAGE_EXISTS_ERROR_MESSAGE_PREFIX) && !force) {
144 log.info("Package skipped because it was already uploaded.");
145 }
146 else {
147 throw new PackageManagerException("Package upload failed: " + msg);
148 }
149
150
151 if (success && replicate) {
152 log.info("Replicate package {}...", path);
153
154 try {
155 post = new HttpPost(url + "/console.html" + new URIBuilder().setPath(path).build().getRawPath() + "?cmd=replicate");
156 HttpClientUtil.applyRequestConfig(post, packageFile, props);
157 }
158 catch (URISyntaxException ex) {
159 throw new PackageManagerException("Invalid path: " + path, ex);
160 }
161
162
163 pkgmgr.executePackageManagerMethodHtmlOutputResponse(httpClient, packageManagerHttpClientContext, post);
164 }
165 }
166
167 @SuppressWarnings("PMD.GuardLogStatement")
168 private void delay(int seconds) {
169 if (seconds > 0) {
170 log.info("Wait {} seconds after package install...", seconds);
171 try {
172 Thread.sleep(seconds * 1000L);
173 }
174 catch (InterruptedException ex) {
175
176 }
177 }
178 }
179
180 private void ensurePackageManagerAvailability(PackageManagerHelper pkgmgr, CloseableHttpClient httpClient, HttpClientContext context) {
181
182 HttpGet get = new HttpGet(url + ".jsp?cmd=help");
183 pkgmgr.executePackageManagerMethodStatus(httpClient, context, get);
184 }
185
186 private PackageInstalledStatus getPackageInstalledStatus(PackageFile packageFile, PackageManagerHelper pkgmgr,
187 CloseableHttpClient httpClient, HttpClientContext context) throws IOException {
188
189 String baseUrl = VendorInstallerFactory.getBaseUrl(url);
190 String packageListUrl = baseUrl + PackageInstalledChecker.PACKMGR_LIST_URL;
191 HttpGet get = new HttpGet(packageListUrl);
192 JSONObject result = pkgmgr.executePackageManagerMethodJson(httpClient, context, get);
193
194 Map<String, Object> props = ContentPackageProperties.get(packageFile.getFile());
195 String group = (String)props.get(PackageProperties.NAME_GROUP);
196 String name = (String)props.get(PackageProperties.NAME_NAME);
197 String version = (String)props.get(PackageProperties.NAME_VERSION);
198
199 PackageInstalledChecker checker = new PackageInstalledChecker(result);
200 return checker.getStatus(group, name, version);
201 }
202
203 }