Skip to content

Commit d0c38cd

Browse files
authored
Added ARU retry for patch conflict checks (#361)
* refactor and simplify patch validation, adding unit tests and i18n for patch conflicts * added retry for ARU conflict check service * move patch conflict message to resource bundle for i18n * remove unused method in FmwInstallerType (deleted unit test and message from bundle) * for translation, changed "groupid" to "GID (group ID)" * refactor overly complex handlePatches, adding new unit tests, and fixing bug with multiple patches error message
1 parent 644b2f0 commit d0c38cd

35 files changed

+1327
-2026
lines changed

imagetool/src/main/java/com/oracle/weblogic/imagetool/aru/AruHttpHelper.java

Lines changed: 1 addition & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1-
// Copyright (c) 2019, 2021, Oracle and/or its affiliates.
1+
// Copyright (c) 2019, 2022, Oracle and/or its affiliates.
22
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
33

44
package com.oracle.weblogic.imagetool.aru;
55

66
import java.io.IOException;
7-
import javax.xml.parsers.ParserConfigurationException;
87
import javax.xml.xpath.XPathExpressionException;
98

109
import com.oracle.weblogic.imagetool.util.HttpUtil;
1110
import com.oracle.weblogic.imagetool.util.XPathUtil;
1211
import org.w3c.dom.Document;
13-
import org.w3c.dom.Element;
14-
import org.w3c.dom.Node;
1512
import org.w3c.dom.NodeList;
1613

1714
/**
@@ -20,8 +17,6 @@
2017
*/
2118
public class AruHttpHelper {
2219
private boolean success;
23-
private Document results;
24-
private String errorMessage;
2520
private final AruProduct product;
2621
private final String userId;
2722
private final String password;
@@ -38,7 +33,6 @@ public class AruHttpHelper {
3833
this.userId = userId;
3934
this.password = password;
4035
this.success = true;
41-
this.results = null;
4236
}
4337

4438
/**
@@ -50,15 +44,6 @@ public class AruHttpHelper {
5044
AruHttpHelper(String userId, String password) {
5145
this(null, userId, password);
5246
}
53-
54-
/**
55-
* Get the error errorMessage.
56-
*
57-
* @return the search error message
58-
*/
59-
String errorMessage() {
60-
return errorMessage;
61-
}
6247

6348
/**
6449
* Returns true if no conflicts ; false if there is conflicts.
@@ -68,15 +53,6 @@ boolean success() {
6853
return success;
6954
}
7055

71-
/**
72-
* Get the result object from the search.
73-
*
74-
* @return dom document detailing about the conflicts
75-
*/
76-
Document results() {
77-
return results;
78-
}
79-
8056
/**
8157
* Return the user for the ARU credentials.
8258
*
@@ -114,123 +90,12 @@ AruHttpHelper execSearch(String url) throws IOException {
11490
return this;
11591
}
11692

117-
/**
118-
* Call ARU via the HTTPUtil methods and check the result for conflict messages about
119-
* patches not compatible.
120-
*
121-
* @param url to the ARU conflict patch numbers site.
122-
* @param payload XML string containing the patch number being validated
123-
* @return this instance of encapsulation of ARU search information
124-
* @throws IOException if the ARU request is not successful
125-
*/
126-
AruHttpHelper execValidation(String url, String payload) throws IOException {
127-
results = HttpUtil.postCheckConflictRequest(url, payload, userId, password);
128-
return this;
129-
}
130-
131-
/**
132-
* Check the resulting document from the execValidation for conflicts.
133-
*
134-
* @return this instance of the encapsulation of the validated results
135-
* @throws IOException if not able to parse the returned Document for conflict messages
136-
*/
137-
AruHttpHelper validation() throws IOException {
138-
NodeList conflictSets;
139-
try {
140-
conflictSets = XPathUtil.nodelist(results(),
141-
"/conflict_check/conflict_sets/set");
142-
} catch (XPathExpressionException xee) {
143-
throw new IOException(xee);
144-
}
145-
if (conflictSets.getLength() > 0) {
146-
try {
147-
success = false;
148-
String expression = "/conflict_check/conflict_sets/set/merge_patches";
149-
150-
NodeList nodeList = XPathUtil.nodelist(results(), expression);
151-
152-
createResultDocument(nodeList);
153-
154-
errorMessage = parsePatchValidationError();
155-
156-
} catch (XPathExpressionException xpe) {
157-
throw new IOException(xpe);
158-
}
159-
return this;
160-
}
161-
return this;
162-
}
163-
164-
/**
165-
* Create an XML document from an XML NodeList.
166-
* @param nodeList partial XML document
167-
* @return a Document based on the NodeList provided
168-
* @throws IOException if an XML parser exception occurs trying to build the document
169-
*/
170-
AruHttpHelper createResultDocument(NodeList nodeList) throws IOException {
171-
try {
172-
Document doc = HttpUtil.documentBuilder().newDocument();
173-
Element element = doc.createElement("results");
174-
175-
for (int i = 0; i < nodeList.getLength(); i++) {
176-
Node n = nodeList.item(i);
177-
Node copyNode = doc.importNode(n, true);
178-
179-
if (n instanceof Element) {
180-
element.appendChild(copyNode);
181-
}
182-
}
183-
184-
doc.appendChild(element);
185-
186-
results = doc;
187-
} catch (ParserConfigurationException pce) {
188-
throw new IOException(pce);
189-
}
190-
return this;
191-
}
192-
193-
/**
194-
* Parses the patch conflict check result and returns a string of patch conflicts grouped by each conflict.
195-
*
196-
* @return String
197-
*/
198-
private String parsePatchValidationError() {
199-
StringBuilder stringBuilder = new StringBuilder();
200-
Node conflictsResultNode = results();
201-
if (conflictsResultNode != null) {
202-
try {
203-
NodeList patchSets = XPathUtil.nodelist(conflictsResultNode, "//merge_patches");
204-
stringBuilder.append("patch conflicts detected: ");
205-
for (int i = 0; i < patchSets.getLength(); i++) {
206-
stringBuilder.append("[");
207-
NodeList bugNumbers = XPathUtil.nodelist(patchSets.item(i), "patch/bug/number"
208-
+ "/text()");
209-
for (int j = 0; j < bugNumbers.getLength(); j++) {
210-
stringBuilder.append(bugNumbers.item(j).getNodeValue());
211-
stringBuilder.append(",");
212-
}
213-
if (bugNumbers.getLength() > 0) {
214-
stringBuilder.deleteCharAt(stringBuilder.length() - 1);
215-
}
216-
stringBuilder.append("]");
217-
}
218-
} catch (XPathExpressionException e) {
219-
return "Exception occurred in parsePatchValidationError: " + e.getMessage();
220-
}
221-
}
222-
return stringBuilder.toString();
223-
}
224-
22593
private void searchResult(Document result) throws IOException {
22694
success = true;
22795
try {
22896
NodeList nodeList = XPathUtil.nodelist(result, "/results/error");
22997
if (nodeList.getLength() > 0) {
23098
success = false;
231-
errorMessage = XPathUtil.string(result, "/results/error/message");
232-
} else {
233-
results = result;
23499
}
235100
} catch (XPathExpressionException xpe) {
236101
throw new IOException(xpe);

imagetool/src/main/java/com/oracle/weblogic/imagetool/aru/AruPatch.java

Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2020, 2021, Oracle and/or its affiliates.
1+
// Copyright (c) 2020, 2022, Oracle and/or its affiliates.
22
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
33

44
package com.oracle.weblogic.imagetool.aru;
@@ -101,6 +101,10 @@ public AruPatch psuBundle(String value) {
101101
return this;
102102
}
103103

104+
public String psuVersion() {
105+
return psuBundle.substring(psuBundle.lastIndexOf(' ') + 1);
106+
}
107+
104108
public boolean isPsu() {
105109
return !Utils.isEmptyString(psuBundle);
106110
}
@@ -231,34 +235,15 @@ public static List<AruPatch> getPatches(Document patchList, String patchSelector
231235
* @throws VersionNotFoundException if the user requested a version that was not in the list.
232236
*/
233237
public static AruPatch selectPatch(List<AruPatch> patches, String providedVersion, String psuVersion,
234-
String installerVersion) throws VersionNotFoundException {
238+
String installerVersion)
239+
throws VersionNotFoundException, MultiplePatchVersionsException {
235240

236241
logger.entering(patches, providedVersion, psuVersion, installerVersion);
237242
AruPatch selected = null;
238243

239-
if (patches.isEmpty()) {
240-
logger.exiting("Patches list is empty");
241-
return null;
242-
}
243-
244-
if (patches.size() == 1) {
245-
selected = patches.get(0);
246-
if (selected.version() == null) {
247-
if (providedVersion != null) {
248-
selected.version(providedVersion);
249-
} else if (psuVersion != null) {
250-
selected.version(psuVersion);
251-
} else {
252-
selected.version(installerVersion);
253-
}
254-
} else if (providedVersion != null && !selected.version().equals(providedVersion)) {
255-
throw new VersionNotFoundException(selected.patchId(), providedVersion, patches);
256-
} else {
257-
logger.info("IMG-0099", selected.patchId(), selected.version(), selected.description());
258-
}
259-
260-
logger.exiting(selected);
261-
return selected;
244+
if (patches.size() < 2) {
245+
// 0 or 1 patch, fill in a patch version and just return what have
246+
return selectPatchOffline(patches, providedVersion, psuVersion, installerVersion);
262247
}
263248

264249
Map<String, AruPatch> patchMap = patches.stream().collect(Collectors
@@ -278,11 +263,42 @@ public static AruPatch selectPatch(List<AruPatch> patches, String providedVersio
278263
selected = patchMap.get(installerVersion);
279264
}
280265

281-
if (selected != null) {
266+
logger.exiting(selected);
267+
if (selected == null) {
268+
throw logger.throwing(new MultiplePatchVersionsException(patches.get(0).patchId(), patches));
269+
} else {
282270
logger.info("IMG-0099", selected.patchId(), selected.version(), selected.description());
271+
return selected;
283272
}
284-
logger.exiting(selected);
285-
return selected;
273+
}
274+
275+
private static AruPatch selectPatchOffline(List<AruPatch> patches, String providedVersion, String psuVersion,
276+
String installerVersion) throws VersionNotFoundException {
277+
AruPatch result = null;
278+
279+
if (patches.isEmpty()) {
280+
logger.fine("Patches list is empty");
281+
} else if (patches.size() == 1) {
282+
result = patches.get(0);
283+
// if the version is filled in, we are working online and there is nothing more to do.
284+
if (result.version() == null) {
285+
// no version means the patch is from the cache. Set the version as best we can.
286+
// TODO: this could be improved if the cache was improved to store patch version.
287+
if (providedVersion != null) {
288+
result.version(providedVersion);
289+
} else if (psuVersion != null) {
290+
result.version(psuVersion);
291+
} else {
292+
result.version(installerVersion);
293+
}
294+
} else if (providedVersion != null && !result.version().equals(providedVersion)) {
295+
throw logger.throwing(new VersionNotFoundException(result.patchId(), providedVersion, patches));
296+
} else {
297+
logger.info("IMG-0099", result.patchId(), result.version(), result.description());
298+
}
299+
}
300+
logger.exiting(result);
301+
return result;
286302
}
287303

288304
/**

0 commit comments

Comments
 (0)