Skip to content
This repository was archived by the owner on Oct 6, 2023. It is now read-only.

Commit 3508862

Browse files
author
sowerstl
committed
Changed error handling in GitLab API logic; (DOECODE-466)
1 parent 6ca3ad8 commit 3508862

File tree

2 files changed

+174
-111
lines changed

2 files changed

+174
-111
lines changed

src/main/java/gov/osti/connectors/api/GitLabAPI.java

Lines changed: 80 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package gov.osti.connectors.api;
22

3+
import com.fasterxml.jackson.databind.JsonNode;
34
import gov.osti.connectors.gitlab.Project;
45
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
56
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -16,6 +17,14 @@
1617
import java.net.URL;
1718
import java.net.URISyntaxException;
1819
import java.net.URLEncoder;
20+
import java.util.ArrayList;
21+
import java.util.Arrays;
22+
import java.util.HashSet;
23+
import java.util.Iterator;
24+
import java.util.List;
25+
import java.util.Map;
26+
import java.util.Map.Entry;
27+
import java.util.Set;
1928
import javax.servlet.http.HttpServletResponse;
2029
import org.apache.commons.lang3.StringUtils;
2130
import org.apache.http.HttpEntity;
@@ -57,6 +66,8 @@ public final class GitLabAPI {
5766
private String currentBranch = "master";
5867
private Namespace currentNamespace = null;
5968

69+
private final Set<Integer> goodResponses = new HashSet<>(Arrays.asList(HttpServletResponse.SC_OK, HttpServletResponse.SC_CREATED, HttpServletResponse.SC_NO_CONTENT));
70+
6071
public static enum HttpType {
6172
GET, POST, PUT;
6273
}
@@ -130,13 +141,7 @@ private String fetch(HttpGet get) throws IOException {
130141
try {
131142
// only return if response is OK
132143
HttpResponse response = hc.execute(get);
133-
int statusCode = response.getStatusLine().getStatusCode();
134-
135-
if (HttpServletResponse.SC_NOT_FOUND == statusCode)
136-
throw new IOException("Failed response: " + HttpServletResponse.SC_NOT_FOUND);
137-
138-
if (HttpServletResponse.SC_OK != statusCode)
139-
throw new IOException("Failed response: " + EntityUtils.toString(response.getEntity()));
144+
processResponse(response);
140145

141146
return EntityUtils.toString(response.getEntity());
142147
} finally {
@@ -168,13 +173,7 @@ private String post(HttpPost post) throws IOException {
168173
try {
169174
// only return if response is OK
170175
HttpResponse response = hc.execute(post);
171-
int statusCode = response.getStatusLine().getStatusCode();
172-
173-
if (HttpServletResponse.SC_NOT_FOUND == statusCode)
174-
throw new IOException("Failed response: " + HttpServletResponse.SC_NOT_FOUND);
175-
176-
if (HttpServletResponse.SC_OK != statusCode && HttpServletResponse.SC_CREATED != statusCode)
177-
throw new IOException("Failed response: " + EntityUtils.toString(response.getEntity()));
176+
processResponse(response);
178177

179178
return EntityUtils.toString(response.getEntity());
180179
} finally {
@@ -206,20 +205,77 @@ private String put(HttpPut put) throws IOException {
206205
try {
207206
// only return if response is OK
208207
HttpResponse response = hc.execute(put);
209-
int statusCode = response.getStatusLine().getStatusCode();
210-
211-
if (HttpServletResponse.SC_NOT_FOUND == statusCode)
212-
throw new IOException("Failed response: " + HttpServletResponse.SC_NOT_FOUND);
213-
214-
if (HttpServletResponse.SC_OK != statusCode)
215-
throw new IOException("Failed response: " + EntityUtils.toString(response.getEntity()));
208+
processResponse(response);
216209

217210
return EntityUtils.toString(response.getEntity());
218211
} finally {
219212
hc.close();
220213
}
221214
}
222215

216+
/**
217+
* Process the API response, based on API validation/error documentation.
218+
*
219+
* @param response the HTTP Response to process
220+
* @return String consolidated error message contents, if not successful
221+
* @throws IOException on IO errors
222+
*/
223+
private String processResponse(HttpResponse response) throws IOException {
224+
// get status code
225+
int statusCode = response.getStatusLine().getStatusCode();
226+
227+
// if successful, just return, no errors to parse
228+
if (goodResponses.contains(statusCode))
229+
return null;
230+
231+
// if not found, throw specific error for special handling
232+
if (HttpServletResponse.SC_NOT_FOUND == statusCode)
233+
throw new IOException("404 Not Found");
234+
235+
// otherwise, get API response body data
236+
String responseString = EntityUtils.toString(response.getEntity());
237+
JsonNode root = MAPPER.readTree(responseString);
238+
239+
// if response has an error, use it
240+
if (root.has("error"))
241+
responseString = root.get("error").asText();
242+
// otherwise, use message info, if exists
243+
else if (root.has("message"))
244+
responseString = parseErrors(root.get("message"));
245+
246+
throw new IOException(responseString);
247+
}
248+
249+
/**
250+
* Recurse into JsonNode pulling out error messages, based on v4 API documentation
251+
*
252+
* @param node the JsonNode to iterate on
253+
* @return String of error message.
254+
*/
255+
private String parseErrors(JsonNode node) {
256+
String errors = "";
257+
Iterator<Entry<String, JsonNode>> fields = node.fields();
258+
259+
while (fields.hasNext()) {
260+
Map.Entry<String, JsonNode> entry = (Map.Entry<String, JsonNode>) fields.next();
261+
262+
String key = entry.getKey();
263+
JsonNode value = entry.getValue();
264+
265+
if (value.isArray()) {
266+
List<String> msgs = new ArrayList<>();
267+
for (final JsonNode msg : value)
268+
if (!StringUtils.isBlank(msg.asText()))
269+
msgs.add(msg.asText());
270+
271+
errors += (StringUtils.isBlank(errors) ? "" : "; ") + "'" + key + "' - " + String.join("|", msgs);
272+
} else if (value.isObject())
273+
errors += (StringUtils.isBlank(errors) ? "" : "; ") + key + ":" + parseErrors(value);
274+
}
275+
276+
return errors;
277+
}
278+
223279
/**
224280
* Construct a GET request to the GitLab API.
225281
*
@@ -472,7 +528,7 @@ public GitLabFile[] fetchTree(String path) throws IOException {
472528
response = fetch(gitLabAPIGet(acquireTreeCmd(path)));
473529
} catch (IOException e) {
474530
// if we didn't find Files on GET, its okay, they just doesn't exist. Return NULL.
475-
if (!e.getMessage().equals("Failed response: " + HttpServletResponse.SC_NOT_FOUND))
531+
if (!e.getMessage().equals("404 Not Found"))
476532
throw e;
477533

478534
return null;
@@ -605,7 +661,7 @@ private Project interfaceWithProject(HttpType type, String body) throws IOExcept
605661
response = fetch(gitLabAPIGet(acquireProjectCmd()));
606662
} catch (IOException e) {
607663
// if we didn't find Project on GET, its okay, it just doesn't exist. Return NULL.
608-
if (!e.getMessage().equals("Failed response: " + HttpServletResponse.SC_NOT_FOUND))
664+
if (!e.getMessage().equals("404 Not Found"))
609665
throw e;
610666

611667
return null;
@@ -649,7 +705,7 @@ public Namespace fetchNamespace(String namespace) throws IOException {
649705
return MAPPER.readValue(response, Namespace.class);
650706
} catch (IOException e) {
651707
// if we didn't find Project, its okay.
652-
if (!e.getMessage().equals("Failed response: " + HttpServletResponse.SC_NOT_FOUND))
708+
if (!e.getMessage().equals("404 Not Found"))
653709
throw e;
654710
}
655711

src/main/java/gov/osti/services/Metadata.java

Lines changed: 94 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,7 +1049,7 @@ private Response doSubmit(String json, InputStream file, FormDataContentDisposit
10491049
} catch ( Exception e ) {
10501050
log.error("OSTI GitLab failure: " + e.getMessage());
10511051
return ErrorResponse
1052-
.internalServerError("Unable to create OSTI Hosted project.")
1052+
.internalServerError("Unable to create OSTI Hosted project: " + e.getMessage())
10531053
.build();
10541054
}
10551055

@@ -1184,7 +1184,7 @@ private Response doAnnounce(String json, InputStream file, FormDataContentDispos
11841184
} catch ( Exception e ) {
11851185
log.error("OSTI GitLab failure: " + e.getMessage());
11861186
return ErrorResponse
1187-
.internalServerError("Unable to create OSTI Hosted project.")
1187+
.internalServerError("Unable to create OSTI Hosted project: " + e.getMessage())
11881188
.build();
11891189
}
11901190

@@ -1911,114 +1911,121 @@ private static void sendPOCNotification(DOECodeMetadata md) {
19111911
* @param md the METADATA to process GitLab for
19121912
*/
19131913
private static void processOSTIGitLab(DOECodeMetadata md) throws Exception {
1914-
// only process OSTI Hosted type
1915-
if (!DOECodeMetadata.Accessibility.CO.equals(md.getAccessibility()))
1916-
return;
1917-
1918-
String fileName = md.getFileName();
1919-
1920-
// sometimes getFileName returns a full path (this should be addressed overall, but temp fix here for now)
1921-
fileName = fileName.substring(fileName.lastIndexOf(File.separator)+1);
1922-
1923-
String codeId = String.valueOf(md.getCodeId());
1924-
java.nio.file.Path uploadedFile = Paths.get(FILE_UPLOADS, String.valueOf(codeId), fileName);
1925-
1926-
// if no file was uploaded, fail
1927-
if (!Files.exists(uploadedFile))
1928-
throw new Exception("File not found in Uploads directory! [" + uploadedFile.toString() + "]");
1929-
1930-
// convert to base64 for GitLab
1931-
String base64Content = convertBase64(new FileInputStream(uploadedFile.toString()));
1914+
try {
1915+
// only process OSTI Hosted type
1916+
if (!DOECodeMetadata.Accessibility.CO.equals(md.getAccessibility()))
1917+
return;
19321918

1933-
if (base64Content == null)
1934-
throw new Exception("Base 64 Content required for OSTI Hosted project!");
1919+
String fileName = md.getFileName();
19351920

1936-
String projectName = "dc-" + md.getCodeId();
1937-
String hostedFolder = "hosted_files";
1921+
// sometimes getFileName returns a full path (this should be addressed overall, but temp fix here for now)
1922+
fileName = fileName.substring(fileName.lastIndexOf(File.separator)+1);
19381923

1939-
String uploadFile = hostedFolder + "/" + fileName;
1924+
String codeId = String.valueOf(md.getCodeId());
1925+
java.nio.file.Path uploadedFile = Paths.get(FILE_UPLOADS, String.valueOf(codeId), fileName);
19401926

1941-
GitLabAPI glApi = new GitLabAPI();
1942-
glApi.setProjectName(projectName);
1927+
// if no file was uploaded, fail
1928+
if (!Files.exists(uploadedFile))
1929+
throw new Exception("File not found in Uploads directory! [" + uploadedFile.toString() + "]");
19431930

1944-
// check existance of project
1945-
Project project = glApi.fetchProject();
1931+
// convert to base64 for GitLab
1932+
String base64Content = convertBase64(new FileInputStream(uploadedFile.toString()));
19461933

1947-
Commit commit = new Commit();
1948-
if (project == null) {
1949-
// create new project, if none exists
1950-
project = glApi.createProject(md);
1934+
if (base64Content == null)
1935+
throw new Exception("Base 64 Content required for OSTI Hosted project!");
19511936

1952-
commit.setBranch(glApi.getBranch());
1953-
commit.setCommitMessage("Adding Hosted Files: " + fileName);
1954-
commit.addBase64ActionByValues("create", uploadFile, base64Content);
1955-
}
1956-
else {
1957-
// edit project, if one already exists
1958-
project = glApi.updateProject(md);
1937+
String projectName = "dc-" + md.getCodeId();
1938+
String hostedFolder = "hosted_files";
19591939

1960-
// for each file in the hosted folder, check against submitted files and process as needed
1961-
GitLabFile[] files = glApi.fetchTree(hostedFolder);
1940+
String uploadFile = hostedFolder + "/" + fileName;
19621941

1963-
int adds = 0;
1964-
int updates = 0;
1965-
int deletes = 0;
1942+
GitLabAPI glApi = new GitLabAPI();
1943+
glApi.setProjectName(projectName);
19661944

1967-
if (files != null) {
1968-
for ( GitLabFile f : files ) {
1969-
if (!f.getType().equalsIgnoreCase("tree")) {
1970-
if (f.getPath().equals(uploadFile)) {
1971-
// update, if filename exists already
1972-
commit.addBase64ActionByValues("update", uploadFile, base64Content);
1945+
// check existance of project
1946+
Project project = glApi.fetchProject();
19731947

1974-
updates++;
1975-
}
1976-
else {
1977-
// delete, if file is not being submitted
1978-
commit.addBase64ActionByValues("delete", f.getPath(), null);
1948+
Commit commit = new Commit();
1949+
if (project == null) {
1950+
// create new project, if none exists
1951+
project = glApi.createProject(md);
19791952

1980-
deletes++;
1953+
commit.setBranch(glApi.getBranch());
1954+
commit.setCommitMessage("Adding Hosted Files: " + fileName);
1955+
commit.addBase64ActionByValues("create", uploadFile, base64Content);
1956+
}
1957+
else {
1958+
// edit project, if one already exists
1959+
project = glApi.updateProject(md);
1960+
1961+
// for each file in the hosted folder, check against submitted files and process as needed
1962+
GitLabFile[] files = glApi.fetchTree(hostedFolder);
1963+
1964+
int adds = 0;
1965+
int updates = 0;
1966+
int deletes = 0;
1967+
1968+
if (files != null) {
1969+
for ( GitLabFile f : files ) {
1970+
if (!f.getType().equalsIgnoreCase("tree")) {
1971+
if (f.getPath().equals(uploadFile)) {
1972+
// update, if filename exists already
1973+
commit.addBase64ActionByValues("update", uploadFile, base64Content);
1974+
1975+
updates++;
1976+
}
1977+
else {
1978+
// delete, if file is not being submitted
1979+
commit.addBase64ActionByValues("delete", f.getPath(), null);
1980+
1981+
deletes++;
1982+
}
19811983
}
19821984
}
19831985
}
1984-
}
19851986

1986-
// right now there is only ever one file, so if we did not updated anything, we need to create it
1987-
if (updates == 0) {
1988-
// create, if there was no matching file to update
1989-
commit.addBase64ActionByValues("create", uploadFile, base64Content);
1987+
// right now there is only ever one file, so if we did not updated anything, we need to create it
1988+
if (updates == 0) {
1989+
// create, if there was no matching file to update
1990+
commit.addBase64ActionByValues("create", uploadFile, base64Content);
19901991

1991-
adds++;
1992-
}
1992+
adds++;
1993+
}
19931994

1994-
String prefix;
1995-
String detail = "\"" + fileName + "\"";
1996-
if (adds == 1 && updates == 0 && deletes == 0) {
1997-
prefix = "Adding";
1998-
}
1999-
else if (adds == 0 && updates == 1 && deletes == 0) {
2000-
prefix = "Updating";
2001-
}
2002-
else {
2003-
prefix = "Modifying";
1995+
String prefix;
1996+
String detail = "\"" + fileName + "\"";
1997+
if (adds == 1 && updates == 0 && deletes == 0) {
1998+
prefix = "Adding";
1999+
}
2000+
else if (adds == 0 && updates == 1 && deletes == 0) {
2001+
prefix = "Updating";
2002+
}
2003+
else {
2004+
prefix = "Modifying";
20042005

2005-
String tmp = (adds == 1) ? "\"" + fileName + "\"" : String.valueOf(adds);
2006-
detail = (adds > 0 ? "Added " + tmp : "");
2006+
String tmp = (adds == 1) ? "\"" + fileName + "\"" : String.valueOf(adds);
2007+
detail = (adds > 0 ? "Added " + tmp : "");
20072008

2008-
tmp = (updates == 1) ? "\"" + fileName + "\"" : String.valueOf(updates);
2009-
detail += (updates > 0 ? (StringUtils.isBlank(detail) ? "" : ", ") + "Updated " + tmp : "");
2009+
tmp = (updates == 1) ? "\"" + fileName + "\"" : String.valueOf(updates);
2010+
detail += (updates > 0 ? (StringUtils.isBlank(detail) ? "" : ", ") + "Updated " + tmp : "");
20102011

2011-
detail += (deletes > 0 ? (StringUtils.isBlank(detail) ? "" : ", ") + "Deleted " + deletes : "");
2012-
}
2012+
detail += (deletes > 0 ? (StringUtils.isBlank(detail) ? "" : ", ") + "Deleted " + deletes : "");
2013+
}
20132014

2014-
commit.setBranch(project.getDefaultBranch());
2015-
commit.setCommitMessage(prefix + " Hosted Files: " + detail);
2016-
}
2015+
commit.setBranch(project.getDefaultBranch());
2016+
commit.setCommitMessage(prefix + " Hosted Files: " + detail);
2017+
}
20172018

2018-
// commit file actions, as needed
2019-
glApi.commitFiles(commit);
2019+
// commit file actions, as needed
2020+
glApi.commitFiles(commit);
20202021

2021-
// override repo link, no matter what
2022-
md.setRepositoryLink(project.getWebUrl());
2022+
// override repo link, no matter what
2023+
md.setRepositoryLink(project.getWebUrl());
2024+
} catch ( Exception e ) {
2025+
// replace non-obvious 'name' with 'software_title' for user clarity
2026+
String eMsg = e.getMessage();
2027+
eMsg = eMsg.replaceFirst("'name'", "'software_title'");
2028+
throw new Exception(eMsg);
2029+
}
20232030
}
20242031
}

0 commit comments

Comments
 (0)