Exception is java.net.ProtocolException: Invalid HTTP method: PATCH - java

I am trying to update user metadata by using HttpURLConnection PATCH API.
I had googled and found this useful link which I used.
[https://stackoverflow.com/questions/25163131/httpurlconnection-invalid-http-method-patch][1]
Following are my steps to update user metadata.
Calling database to get user information which need to be
updated, suppose database return 1000 users
.
Calling GET xxx/users/{userId} API 1000 times to check whether
database user exists or not,
Suppose GET xxx/users/{userId} API return 800 active users which
needs to be updated afterwards
Calling PATCH xxx/users/{userId} API 800 times to update user
metadata.
My code working fine if record size is less than or equal to 200-250 but If size gets increase say 1000 then application throwing exception saying
Exception is java.net.ProtocolException: Invalid HTTP method: PATCH
Here is my code.
public static void main(String[] args) throws FileNotFoundException, IOException {
// Here calling DB to get user metadata
List<CEUser> ca = getUserMetada(prop);
// Calling GET users/{userId} API to check whether user exists or not
List<CEUser> activeUsers = getActiveUsers(ca, prop);
// Calling PATCH users/{userId} API to update user metadata
updateUsername(activeUsers, prop);
}
public List<CEUser> getActiveUsers(List<CEUser> CEUsers, Properties prop) {
try {
List<CEUser> activeCEUsers = new ArrayList<>();
for (CEUser ca : CEUsers) {
URL url = new URL(prop.getCeBaseURL() + "users/" + ca.getUserId());
HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
httpConnection.setRequestMethod("GET");
httpConnection.setRequestProperty("Accept", "application/json");
httpConnection.connect();
if (httpConnection.getResponseCode() == 200)
activeCEUsers.add(ca);
httpConnection.disconnect();
}
return activeCEUsers;
} catch (Exception e) {
System.out.println("Exception occurred in getActiveUsers() method ");
}
}
private static void allowMethods(String... methods) {
try {
Field methodsField = HttpURLConnection.class.getDeclaredField("methods");
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(methodsField, methodsField.getModifiers() & ~Modifier.FINAL);
methodsField.setAccessible(true);
String[] oldMethods = (String[]) methodsField.get(null);
Set<String> methodsSet = new LinkedHashSet<>(Arrays.asList(oldMethods));
methodsSet.addAll(Arrays.asList(methods));
String[] newMethods = methodsSet.toArray(new String[0]);
methodsField.set(null/*static field*/, newMethods);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
public List<CEUser> updateUsername(List<CEUser> ceUsers, Properties prop) {
try {
allowMethods("PATCH");
List<CEUser> updatedUsername = new ArrayList<>();
for (CEUser ca : ceUsers) {
// Construct username
String username = "some static email";
// Construct email into json format to set in body part
String json = constructJson("email", username);
URL url = new URL(prop.getCeBaseURL() + "users/" + ca.getUserId());
HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
httpConnection.setRequestMethod("PATCH");
httpConnection.setDoOutput(true);
httpConnection.setRequestProperty("Accept-Charset", "UTF-8");
httpConnection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
try (OutputStream output = httpConnection.getOutputStream()) {
output.write(json.getBytes("UTF-8"));
}
httpConnection.connect();
if (httpConnection.getResponseCode() == 200) {
ca.setUsername(username); // set updated username
updatedUsername.add(ca);
}
httpConnection.disconnect();
}
return updatedUsername;
} catch (Exception e) {
System.out.println("Exception occurred in updateUsername() method");
}
}
Any idea why same code working for 200-250 records but not for 1000 records.
Thanks

Related

Status code 404 when calling spring-boot API, but not for postman or browser

I want to make an API call to a local REST server built with Spring-Boot which is interacting with mongodb. I already checked some posts which I found to this topic, but my problem seems to be a little bit different.
Here are some code snippets which are relevant:
protected static CoreEntity[] sendGET(CoreEntity[] resultList, String path) throws IOException {
path = String.join("%20", path.split(" "));
return handleResponse(resultList, getConnection(path, "Get"));
}
private static HttpURLConnection getConnection(String path, String requestMethod) throws IOException {
URL url = new URL(REQUEST_URL + path);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("accept", "application/json");
connection.setConnectTimeout(50000);
connection.setReadTimeout(50000);
connection.setRequestMethod(requestMethod);
initializeGSON();
return connection;
}
private static CoreEntity[] handleResponse(CoreEntity[] resultList, HttpURLConnection connection) {
try {
final int status = connection.getResponseCode();
if (status == HttpURLConnection.HTTP_OK) { // Success
try (InputStreamReader reader = new InputStreamReader(connection.getInputStream()); BufferedReader in = new BufferedReader(reader)) {
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) { response.append(inputLine); }
reader.close();
in.close();
JSONArray jsonArray = getJSONAsArray(response.toString());
resultList = (CoreEntity[]) Array.newInstance(resultList.getClass().getComponentType(), jsonArray.length());
for (int i = 0; i < jsonArray.length(); i++)
resultList[i] = (CoreEntity) GSON.fromJson(jsonArray.get(i).toString(), resultList.getClass().getComponentType());
} catch (IOException | JSONException e) { e.printStackTrace(); }
} else {
System.out.println("\nRequest failed with error code: " + status);
}
connection.disconnect();
return resultList;
} catch (ConnectException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
The response for http://www.google.com or any other homepage is successful with status code 200. But as soon as I call my API I get an error with status code 404. Strange is that everything works when I am using Postman or the browser. So when I do a get request via postman to the following method (http://localhost:8080/pets/3), I can see the print out and get the data from mongodb, but not for the code above. For the code above nothing happens on server side, no print out, no exception, nothing.
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ResponseEntity<T> getById(#PathVariable final long id) {
System.out.println("TEST ===> " + id);
T entity = getService().getById(id);
return entity == null ? ResponseEntity.notFound().build() : ResponseEntity.ok(entity);
}
It seems like my application is not able to find the API, but I already verified that the URL is correct which is why I don’t understand the error code 404.
I also read about package visibility, but my structure looks like the following which is why I don't think that this is the reason.
Package Structure (Don't be confused from name Aerospike)
I've spend way too much time for this now, and I am really desperate for help and hope you can help me or at least point me in the right direction.
Edit
Here is the entire RestController:
#Controller
public abstract class CoreController<S extends CoreService<T>, T extends CoreEntity> {
public static final String SERVER = "http://localhost", PORT = ":8080",
CORE_API = SERVER + PORT + "/"; // controller/v2/
public static final String ID = "id";
private String api;
public CoreController() { }
public CoreController(final String api) { this.api = CORE_API + api; }
#RequestMapping(value = "/{" + ID + "}", method = RequestMethod.GET)
public ResponseEntity<T> getById(#PathVariable final long id) {
System.out.println("TEST ===> " + id);
T entity = getService().getById(id);
return entity == null ? ResponseEntity.notFound().build() : ResponseEntity.ok(entity);
}
public abstract S getService();
}
#Controller
#RequestMapping(value = "pets/")
public class PetController extends CoreController<PetService, Pet> {
#Autowired
protected PetService service;
public static final String API = "pets";
public PetController() { super(API); }
public PetService getService() { return service; }
}
Here the evidence that the spring-boot is listening on 8080 and also postman works with port 8080.
Server print out on start up
I think you missing the slash ("/") in the start and you have duplicate in the end of the exposed value so it's looking for pets//{id} in the controller change to value = { "/pets"}
Anyway, when starting the service syou should see in the logs the exposed uri's

How to check if website link has data (picture) or website is invalid?

I want to test if website has data in it or it's invalid link in android studio. For example:
Has data:
https://media-cdn.tripadvisor.com/media/photo-o/03/d8/a8/70/zinfandel-s.jpg
Has no data cause link is invalid:
https://media-cdn.tripadvisor.com/media/po/03/d8/a8/70/zdel-s.jpg
We can also use java.net.url class to validate a URL. A MalformedURLExceptio will be thrown if no protocol is specified, or an unknown protocol is found, or spec is null. Then we will call method toURI()that will throw a URISyntaxException if the URL cannot be converted to URI
class URLValidator {
public static boolean urlValidator(String url) {
try {
new URL(url).toURI();
return true;
}
catch (URISyntaxException exception) {
return false;
}
catch (MalformedURLException exception) {
return false;
}
}
public static void main(String[] args)
{
String url = "https://media-cdn.tripadvisor.com/media/po/03/d8/a8/70/zdel-s.jpg";
if (urlValidator(url))
System.out.print("The given URL: " + url + " , contain image.");
else
System.out.print("The given URL: " + url + " , is not contain image.");
}
}
well, you can use okhttp library for maing http-requests.
here's the snippet for you:
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
Request request = new Request.Builder()
.url("https://media-cdn.tripadvisor.com/media/po/03/d8/a8/70/zdel-s.jpg")
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
//this will run if image is not available
}
}
}

Programmatically retrieve all repositories under my Github account using Jgit

I'm having a bit of a challenge with the JGit client. I'm embedding it in a Java App & I'd like to fetch all the repositories under an account on Github and display them. Also to add on, can I create a repository direct on Github using JGit. Like Create a Remote Repository?
I've gone through this link but it seems generic to me. Thanks in advance
The List user repositories API is something you can call from any language (including Java) and is not related to JGit.
GET /users/:username/repos
An example of Java library making those calls would be "GitHub API for Java ", and its java.org.kohsuke.github.GHPerson.java#listRepositories() method
new PagedIterator<GHRepository>(
root.retrieve().asIterator("/users/" + login + "/repos?per_page=" + pageSize,
GHRepository[].class, pageSize))
Once you get the url for those user repos, you can create JGit repos out of them.
I also doing that same Requirement To get List of repositories of a particular user
Try this one you will get All repositories of that user
//Here name means username of GitHub account
public Collection<AuthMsg> getRepos(String name) {
String url = "https://api.github.com/users/"+name+"/repos";
String data = getJSON(url);
System.out.println(data);
Type collectionType = new TypeToken<Collection<AuthMsg>>(){}.getType();
Collection<AuthMsg> enums = new Gson().fromJson(data, collectionType);
return enums;
}
//getJson method
public String getJSON(String url) {
HttpURLConnection c = null;
try {
URL u = new URL(url);
c = (HttpURLConnection) u.openConnection();
c.setRequestMethod("GET");
c.setRequestProperty("Content-length", "0");
c.setUseCaches(false);
c.setAllowUserInteraction(false);
c.connect();
int status = c.getResponseCode();
switch (status) {
case 200:
case 201:
BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line+"\n");
}
br.close();
return sb.toString();
}
} catch (MalformedURLException ex) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
} finally {
if (c != null) {
try {
c.disconnect();
} catch (Exception ex) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
}
}
}
return null;
}
//AuthMsg Class
public class AuthMsg {
//"name" which is in json what we get from url
#SerializedName("name")
private String repository;
/**
* #return the repository
*/
public String getRepository() {
return repository;
}
/**
* #param repository the repository to set
*/
public void setRepository(String repository) {
this.repository = repository;
}
}

How to load custom XML feed with Jsoup?

I have a Java-method that gets a feed-document (via http) and then parses the feed (which is not of-type JSON or XML).
This is the method:
public ArrayList<ArrayList<String>> getFeed(String type)
{
String feed = "";
String address = "";
Document file;
/**
* FEED URLs-------\/
*/
switch (type) {
case "news":
address = "https://[domain]/svc/feeds/news/6001?subtree=false&imagesize=medium-square";
break;
case "events":
address = "http://[domain]/svc/feeds/events/6001?subtree=true&imagesize=medium-square&from=%5bfromDate%5d&to=%5btoDate";
}
try {
HttpURLConnection connection = (HttpURLConnection) (new URL(address)).openConnection();
//TODO: #Test
//----------------------------\/--THIS ONE WILL CAUSE ERRORS!!
file = (Document)connection.getContent();
connection.disconnect();
//OUTPUT
feed = file.getElementsByAttribute("pre").text();
stream = new StringReader(feed);
} catch (Exception e) {}
//BEGIN PARSING\\//--THEN OUTPUT//\\
try {
return parse();
} catch (FeedParseException e) {}
//de-fault
return null;
}
It's not working; saying that object:'file' caused NullPointerException.
So how do I increase my precision in debugging something which seems to me to be non-Open-Source.
P.S.: I'm not testing the "events" case so don't worry about the GET-parameters there.
here's my stack-trace:
I don't see how it helps though...
You can pass to Jsoup the URL object directly.
Instead of:
HttpURLConnection connection = (HttpURLConnection) (new URL(address)).openConnection();
//TODO: #Test
//----------------------------\/--THIS ONE WILL CAUSE ERRORS!!
file = (Document)connection.getContent();
connection.disconnect();
do
file = Jsoup //
.connect(address) //
.timeout( 10 * 1000) //
.ignoreContentType(true) //
.get();
Jsoup 1.8.3

How to calculate a file size from URL in java

I'm attempting to get a bunch of pdf links from a web service and I want to give the user the file size of each link.
Is there a way to accomplish this task?
Thanks
Using a HEAD request, you can do something like this:
private static int getFileSize(URL url) {
URLConnection conn = null;
try {
conn = url.openConnection();
if(conn instanceof HttpURLConnection) {
((HttpURLConnection)conn).setRequestMethod("HEAD");
}
conn.getInputStream();
return conn.getContentLength();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if(conn instanceof HttpURLConnection) {
((HttpURLConnection)conn).disconnect();
}
}
}
The accepted answer is prone to NullPointerException, doesn't work for files > 2GiB and contains an unnecessary call to getInputStream(). Here's the fixed code:
public long getFileSize(URL url) {
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("HEAD");
return conn.getContentLengthLong();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
Update: The accepted was updated but still has issues.
Try to use HTTP HEAD method. It returns the HTTP headers only. The header Content-Length should contain information you need.
Did you try already to use getContentLength on the URL connection?
In case the server responses a valid header you should get the size of the document.
But be aware of the fact that the webserver might also return the file in chunks. In this case IIRC the content length method will return either the size of one chunk (<=1.4) or -1 (>1.4).
The HTTP response has a Content-Length header, so you could query the URLConnection object for this value.
Once the URL connection has been opened, you can try something like this:
List values = urlConnection.getHeaderFields().get("content-Length")
if (values != null && !values.isEmpty()) {
// getHeaderFields() returns a Map with key=(String) header
// name, value = List of String values for that header field.
// just use the first value here.
String sLength = (String) values.get(0);
if (sLength != null) {
//parse the length into an integer...
...
}
}
In case you are on Android, here's a solution in Java:
/**#return the file size of the given file url , or -1L if there was any kind of error while doing so*/
#WorkerThread
public static long getUrlFileLength(String url) {
try {
final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
urlConnection.setRequestMethod("HEAD");
final String lengthHeaderField = urlConnection.getHeaderField("content-length");
Long result = lengthHeaderField == null ? null : Long.parseLong(lengthHeaderField);
return result == null || result < 0L ? -1L : result;
} catch (Exception ignored) {
}
return -1L;
}
And in Kotlin:
/**#return the file size of the given file url , or -1L if there was any kind of error while doing so*/
#WorkerThread
fun getUrlFileLength(url: String): Long {
return try {
val urlConnection = URL(url).openConnection() as HttpURLConnection
urlConnection.requestMethod = "HEAD"
urlConnection.getHeaderField("content-length")?.toLongOrNull()?.coerceAtLeast(-1L)
?: -1L
} catch (ignored: Exception) {
-1L
}
}
If your app is from Android N, you can use this instead:
/**#return the file size of the given file url , or -1L if there was any kind of error while doing so*/
#WorkerThread
fun getUrlFileLength(url: String): Long {
return try {
val urlConnection = URL(url).openConnection() as HttpURLConnection
urlConnection.requestMethod = "HEAD"
urlConnection.contentLengthLong.coerceAtLeast(-1L)
} catch (ignored: Exception) {
-1L
}
}
You can try this..
private long getContentLength(HttpURLConnection conn) {
String transferEncoding = conn.getHeaderField("Transfer-Encoding");
if (transferEncoding == null || transferEncoding.equalsIgnoreCase("chunked")) {
return conn.getHeaderFieldInt("Content-Length", -1);
} else {
return -1;
}

Categories

Resources