Hi there,
Your API REST is real good, and I have almost finished the implementation of a single Java client to consume most of your methods, but I have found only one problem with the submission files POST method. Due to technical restrictions Im not allowed to use CURL so I have to use HttpURLConnection and Im receiving constantly a response with 400 Error. After reading the PHP definition I have wrote this quite common Java method:
....
private void testConsumerPOST(String array, String nombreProblema, String languageId, String contest_id) { String servletURL = "http://localhost/domjudge/api/submissions";
URL servlet = null; try {
TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; }
public void checkClientTrusted(X509Certificate[] certs, String authType) { }
public void checkServerTrusted(X509Certificate[] certs, String authType) { }
} };
SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier HostnameVerifier allHostsValid = new HostnameVerifier() { public boolean verify(String hostname, SSLSession session) { return true; } }; // Install the all-trusting host verifier HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
servlet = new URL(servletURL); HttpURLConnection servletConnection = (HttpURLConnection) servlet.openConnection();
// AUTENTICACION String userpass = "admin:admin"; String basicAuth = "Basic " + new String(new com.sun.org.apache.xerces.internal.impl.dv.util.Base64().encode(userpass.getBytes())); servletConnection.setRequestProperty("Authorization", basicAuth);
servletConnection.setRequestMethod("POST"); servletConnection.setDoOutput(true); servletConnection.setDoInput(true);
OutputStreamWriter out = new OutputStreamWriter(servletConnection.getOutputStream()); ObjectMapper mapper = new ObjectMapper(); Map<String, Object> data = new HashMap<String, Object>();
data.put("code[]", array); data.put("shortname", nombreProblema); data.put("langid", languageId); data.put("contest", contest_id);
out.write(mapper.writeValueAsString(data)); out.flush();
if (servletConnection.getResponseCode() != HttpURLConnection.HTTP_CREATED) { throw new RuntimeException("Failed : HTTP error code : " + servletConnection.getResponseCode()); }
BufferedReader br = new BufferedReader(new InputStreamReader( (servletConnection.getInputStream())));
String output; System.out.println("Output from Server .... \n"); while ((output = br.readLine()) != null) { System.out.println(output); }
out.close();
} catch (MalformedURLException ex) { Logger.getLogger(PostSubmission.class.getName()).log(Level.SEVERE, null, ex); } catch (ProtocolException ex) { Logger.getLogger(PostSubmission.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException ex) { Logger.getLogger(PostSubmission.class.getName()).log(Level.SEVERE, null, ex); } catch (KeyManagementException ex) { Logger.getLogger(PostSubmission.class.getName()).log(Level.SEVERE, null, ex); } catch (NoSuchAlgorithmException ex) { Logger.getLogger(PostSubmission.class.getName()).log(Level.SEVERE, null, ex); } }
Also another one with binary data post almost identical:
private void testConsumerPOST_Binary(String array, String nombreProblema, String languageId, String contest_id) { String servletURL = "http://192.168.1.146/domjudge/api/submissions";
try {
TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; }
public void checkClientTrusted(X509Certificate[] certs, String authType) { }
public void checkServerTrusted(X509Certificate[] certs, String authType) { }
} };
SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier HostnameVerifier allHostsValid = new HostnameVerifier() { public boolean verify(String hostname, SSLSession session) { return true; } }; // Install the all-trusting host verifier HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
HttpURLConnection httpcon = (HttpURLConnection) ((new URL(servletURL).openConnection())); httpcon.setDoOutput(true); httpcon.setRequestProperty("Content-Type", "application/json"); httpcon.setRequestProperty("Accept", "application/json"); httpcon.setRequestMethod("POST");
String userpass = "admin:admin"; String basicAuth = "Basic " + new String(new com.sun.org.apache.xerces.internal.impl.dv.util.Base64().encode(userpass.getBytes())); httpcon.setRequestProperty("Authorization", basicAuth);
httpcon.connect();
ObjectMapper mapper = new ObjectMapper(); //Jackson Object mapper Map<String, Object> data = new HashMap<String, Object>();
data.put("code[]", array); data.put("shortname", nombreProblema); data.put("langid", languageId); data.put("contest", contest_id);
byte[] outputBytes = mapper.writeValueAsString(data).getBytes("UTF-8"); OutputStream os = httpcon.getOutputStream(); os.write(outputBytes); os.flush();
if (httpcon.getResponseCode() != HttpURLConnection.HTTP_CREATED) { throw new RuntimeException("Failed : HTTP error code : " + httpcon.getResponseCode()); }
//Get the new submission_id BufferedReader br = new BufferedReader(new InputStreamReader( (httpcon.getInputStream())));
String output; System.out.println("Output from Server .... \n"); while ((output = br.readLine()) != null) { System.out.println(output); }
os.close();
} catch (MalformedURLException ex) { Logger.getLogger(PostSubmission.class.getName()).log(Level.SEVERE, null, ex); } catch (ProtocolException ex) { Logger.getLogger(PostSubmission.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException ex) { Logger.getLogger(PostSubmission.class.getName()).log(Level.SEVERE, null, ex); } catch (KeyManagementException ex) { Logger.getLogger(PostSubmission.class.getName()).log(Level.SEVERE, null, ex); } catch (NoSuchAlgorithmException ex) { Logger.getLogger(PostSubmission.class.getName()).log(Level.SEVERE, null, ex); } }
None of them are able to submit the files, just to be clear about the data format Im sending:
code[] ---> "[{"filename":"main.cpp","content":"I2luY2x1ZGUgPGlvc3RyZWFtPg0KI2luY2x1ZGUgPHN0ZGlvLmg+DQoNCnVzaW5nIG5hbWVzcGFjZSBzdGQ7DQoNCmludCBtYWluKCkNCnsNCiAgICBTdHJpbmcgbm9tYnJlPSJwZWRybyI7DQoJaW50IHZhbD0xLHZhMj0xMCx0b3RhbD0wOw0KCXRvdGFsPXZhbCt2YWwyOw0KCQ0KCQ0KICAgIHJldHVybiAwOw0KfQ0K"}]"
shortname ---> The problem ddbb shortname value previously recovered with the "problems GET method of the API REST"
langid---> The language id value previously recovered with the "problems GET method of the API REST" (Ex: cpp)
contest ---> We have tried both contestId and contest_short_name. Im not sure wich one should be sent.
My last question is: Is the teamId necessary for the post?
We would thank any of your comments to finish this amazing program!!!
Thanks in advance [😊]
Javier.