The following code is my sample servlet application
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userEmail = request.getPathInfo().split("/")[1];
saveEmails(response, userEmail);
}
protected void saveEmails(HttpServletResponse response, String email) {
ArrayList<String> userEmails = (ArrayList<String>)getServletContext().getAttribute("userEmails");
if (userEmails == null) {
System.out.println("creating a new linked list");
ArrayList<String> newUserEmails = new ArrayList<String>();
newUserEmails.add(email);
getServletContext().setAttribute("userEmails", newUserEmails);
} else {
System.out.println("appending new email into linked list");
getServletContext().setAttribute("userEmails", userEmails.add(email));
}
System.out.println(userEmails);
}
Whenever I make the first (localhost/value1) and second (localhost/value2) requests it (getServletContext().getAttribute("userEmails")) prints out the following
[value1]
[value1,value2]
However whenever I make the third (localhost/value3) request it always converts LinkedList into boolean and prints out the following error
HTTP Status 500 - java.lang.Boolean cannot be cast to java.util.LinkedList
I'm not sure what's going on, do I need to configure something in my web.xml?
List.add() returns a boolean, so on the second time when you call userEmails.add(email) the attribute is replaced by a Boolean.
You don't need to keep setting the attribute after you've put it in the context the first time (unless you want to replace the whole list). Just replace
getServletContext().setAttribute("userEmails", userEmails.add(email));
with
userEmails.add(email);
Related
I have brief understanding on multi threading in Java web apps. However, I came across an issue while developing our android app which communicates with the server via REST.
Our web application is based on Apache Wicket 8.6 and contains additional HttpServlet endpoints. One endpoint is applied while uploading images from the app via post. This works fine as long as I am uploading only one image at a time. If I perform multiple upload requests in my android app in a quick succession (some milliseconds), only the last upload is performed successfully (it is working fine when I put a second break between the uploads). It seems, as if all requests except the last one are missing the image content read from the input stream of the servlet request. Thus, I am guessing, that I am having a threading problem with my servlet. I would appreciate, if someone could guide me in the right direction to solve this issue.
public class MyServlet extends HttpServlet{
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
boolean proceed =true;
Map<String,String[]> parameters = req.getParameterMap();
if(parameters!=null){
//read some parameters which specify the request
}
if(proceed) {
InputStream is = req.getInputStream();
if(is!=null) {
//The result of this output is 0 for the first requests only for the last request it is 1
System.err.println("Stream size: "+is.available());
//do something
}
}
//do something....
}
}
I could, of course, write the images in my android app in one request using multipart but still I'd like to make the servlet thread safe for the occasion that it gets two requests at the same time.
I appreciate your help.
So, after some additional research I discovered, that the input stream is not empty even is.available() returns 0
My problem was something different. I save the uploaded image in a ModeShape repository. The repository session is stored in the wicket application instance. THus, only one ModeSHape repository session exists. When writing the image, it seems as if there was a problem with the ModeShape session. Thus, I put the ModeShape session in a synchronized block and now everything runs fine.
public class MyServlet extends HttpServlet{
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
boolean proceed =true;
Map<String,String[]> parameters = req.getParameterMap();
if(parameters!=null){
//read some parameters which specify the request
}
if(proceed) {
String fileName = req.getHeader("fileName");
if(!StringUtils.isEmpty(fileName)) {
InputStream is = req.getInputStream();
if(is!=null) {
//The result of this output is 0 for the first requests only for the last request it is 1
System.err.println("Stream size: "+is.available());
WicketApplication app=null;
try {
app = (WicketApplication)Application.get("wicket");
} catch (Exception e) {
LOG.error("Error while generating WicketApplication object for project "+project.getName(),e);
}
if(app!=null) {
final Session repoSession = app.getRepoSession();
synchronized (repoSession) {
//write image to repository
}
}
}
}
}
//do something....
}
}
I am trying to figure out how to determine if all async HTTP GET requests I've made have completed, so that I can execute another method. For context, I have something similar to the code below:
public void init() throws IOException {
Map<String, CustomObject> mapOfObjects = new HashMap<String, CustomObject>();
ObjectMapper mapper = new ObjectMapper();
// some code to populate the map
mapOfObjects.forEach((k,v) -> {
HttpClient.asyncGet("https://fakeurl1.com/item/" + k, createCustomCallbackOne(k, mapper));
// HttpClient is just a wrapper class for your standard OkHTTP3 calls,
// e.g. client.newcall(request).enqueue(callback);
HttpClient.asyncGet("https://fakeurl2.com/item/" + k, createCustomCallbackTwo(k, mapper));
});
}
private createCustomCallbackOne(String id, ObjectMapper mapper) {
return new Callback() {
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
try (ResponseBody body = response.body()) {
CustomObject co = mapOfObjects.get(id);
if (co != null) {
co.setFieldOne(mapper.readValue(body.byteStream(), FieldOne.class)));
}
} // implicitly closes the response body
}
}
#Override
public void onFailure(Call call, IOException e) {
// log error
}
}
}
// createCustomCallbackTwo does more or less the same thing,
// just sets a different field and then performs another
// async GET in order to set an additional field
So what would be the best/correct way to monitor all these asynchronous calls to ensure they have completed and I can go about performing another method on the Objects stored inside the map?
The most simple way would be to keep a count of how many requests are 'in flight'. Increment it for each request enqueued, decrement it at the end of the callback. When/if the count is 0, any/all requests are done. Using a semaphore or counting lock you can wait for it to become 0 without polling.
Note that the callbacks run on separate threads, so you must provide some kind of synchronization.
If you want to create a new callback for every request, you could use something like this:
public class WaitableCallback implements Callback {
private boolean done;
private IOException exception;
private final Object[] signal = new Object[0];
#Override
public void onResponse(Call call, Response response) throws IOException {
...
synchronized (this.signal) {
done = true;
signal.notifyAll();
}
}
#Override
public void onFailure(Call call, IOException e) {
synchronized (signal) {
done = true;
exception = e;
signal.notifyAll();
}
}
public void waitUntilDone() throws InterruptedException {
synchronized (this.signal) {
while (!this.done) {
this.signal.wait();
}
}
}
public boolean isDone() {
synchronized (this.signal) {
return this.done;
}
}
public IOException getException() {
synchronized (this.signal) {
return exception;
}
}
}
Create an instance for every request and put it into e.g. a List<WaitableCallback> pendingRequests.
Then you can just wait for all requests to be done:
for ( WaitableCallback cb : pendingRequests ) {
cb.waitUntilDone();
}
// At this point, all requests have been processed.
However, you probably should not create a new identical callback object for every request. Callback's methods get the Call passed as parameter so that the code can examine it to figure out which request it is processing; and in your case, it seems you don't even need that. So use a single Callback instance for the requests that should be handled identically.
If the function asyncGet calls your function createCustomCallbackOne then its easy.
For each key you are calling two pages. "https://fakeurl1.com/item/" and "https://fakeurl2.com/item/" (left out + k)
So you need a map to trach that and just one call back function is enough.
Use a map with key indicating each call:
static final Map<String, Integer> trackerOfAsyncCalls = new HashMap<>();
public void init() throws IOException {
Map<String, CustomObject> mapOfObjects = new HashMap<String, CustomObject>();
//need to keep a track of the keys in some object
ObjectMapper mapper = new ObjectMapper();
trackerOfAsyncCalls.clear();
// some code to populate the map
mapOfObjects.forEach((k,v) -> {
HttpClient.asyncGet("https://fakeurl1.com/item/" + k, createCustomCallback(k,1 , mapper));
// HttpClient is just a wrapper class for your standard OkHTTP3 calls,
// e.g. client.newcall(request).enqueue(callback);
HttpClient.asyncGet("https://fakeurl2.com/item/" + k, createCustomCallback(k, 2, mapper));
trackerOfAsyncCalls.put(k + "-2", null);
});
}
//final important
private createCustomCallbackOne(final String idOuter, int which, ObjectMapper mapper) {
return new Callback() {
final String myId = idOuter + "-" + which;
trackerOfAsyncCalls.put(myId, null);
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
trackerOfAsyncCalls.put(myId, 1);
///or put outside of if if u dont care if success or fail or partial...
Now set up a thread or best a schduler that is caclled every 5 seconds, check all eys in mapOfObjects and trackerOfAsyncCalls to see if all keys have been started and some final success or timeout or error status has been got for all.
I'm doing an API in my web system because of a task in university. The problem is that I'm not able to do a specific part and I think that it's very easy.
The statement says:
*GET /rest/api/v1/tfg?State = ${state}
List of all TFGs in the indicated state. You can indicate different states at the same time. To do this, you must repeat the state parameter multiple times (such as: "?State=state1&State=state2&State=state3"), and the web service will return all those who are in any of these states.*
I have a DB with projects (TFGs) and I know how to get this data, but the problems are that I don't know what to do to detect ? in URL, and how can I do to read different parameters depending on the quantity. It's possible to have one state or N states. How can I do it?
The current code is this:
#Path("/rest/api/v1/tfg")
public class TfgREST {
#GET
#Path("")
#Produces(MediaType.APPLICATION_JSON)
public Response findAll() throws ServletException, IOException {
TfgDao dao = new TfgDao();
LinkedList<Projecte> llista = dao.findAll(true); //TRUE because of API
JsonArrayBuilder array = Json.createArrayBuilder();
for(Projecte p : llista){
array.add(p.getTitol());
}
return Response.ok(array.build()).build();
}
#GET
#Path("/?state={state}")
#Produces(MediaType.APPLICATION_JSON)
public Response findByState(#PathParam("state") String state) throws ServletException, IOException {
TfgDao dao = new TfgDao();
LinkedList<String> llista = dao.findByState(state);
//JsonObjectBuilder jo = Json.createObjectBuilder();
JsonArrayBuilder array = Json.createArrayBuilder();
for(String p : llista){
array.add(p);
}
return Response.ok(array.build()).build();
}
If I call http://...../rest/api/v1/tfg?State=XXXX, web invokes the first one (findAll) but, if I use /rest/api/v1/tfg/State=XXX it works...
Thanks for all! I'm waiting for your answers.
Miquel
Because REST API follows resource.
if "state" is a object, you can use /rest/api/v1/tfg/State=XXX
BUT if "state" is only a property of tfg, you use /rest/api/v1/tfg?State=XXX
Ok guys, now it's working. I publish the solution in order to contribute with you and try to solve this problem in a future for other people.
I mixed both methods in one implemeting an if.
The code is the following:
#Path("/rest/api/v1/tfg")
public class TfgREST {
#GET
#Path("")
#Produces(MediaType.APPLICATION_JSON)
public Response findAll(#QueryParam("state") List<String> state) throws ServletException, IOException {
TfgDao dao = new TfgDao();
JsonArrayBuilder array = Json.createArrayBuilder();
if(state.isEmpty()){
LinkedList<Projecte> llista = dao.findAll(true); //TRUE because of API
for(Projecte p : llista){
array.add(p.getTitol());
}
}
else{
LinkedList<String> projs;
for (String s : state){
projs = dao.findByState(s);
for (String x : projs){
array.add(x);
}
}
}
return Response.ok(array.build()).build();
}
}
Thanks for your contributions, I finally got it, and it has been very easy!
I have a dataset of 230'000 entries in a csv file. 1 line looks like this:
1849-06-01,24.844,1.402,Abidjan,Côte D'Ivoire,5.63N,3.23W
now when I tried splitting the entries into an array, then creating an object and adding latter object to an arraylist, I failed. I later noticed that it has to do with the number of entries I try it with. I found 20'000 to be the absolute maximum. My parser looks like this:
try {
new RequestBuilder(RequestBuilder.GET, "test20.csv").sendRequest("", new RequestCallback() {
String data[] = new String[20000];
#Override
public void onResponseReceived(Request req, Response resp) {
String text = resp.getText();
data = text.split("\n");
for(String str: data) {
String[] results = new String[6];
results = str.split(",");
// creates DataTableObject using the constructor
DataTableObject object = new DataTableObject(results[0], results[1], results[2], results[3], results[4], results[5], results[6]);
dataSet.add(object);
}
drawTable(dataSet);
}
#Override
public void onError(Request res, Throwable throwable) {
// handle errors
}
});
} catch (RequestException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
the drawTable() method just inserts all the created objects into a flextable.
dataSet is an ArrayList<DataTableObject>, those objects just contain all the Strings (city, country, etc.)
the whole thing runs with GWT 2.7.0 and JDK 1.8.
Do you have any idea on how to be able to draw all the 230'000 entries without hitting a timeout in the browser?
I've tried working without objects, but that doesn't cut down the runtime notably. Neither does only splitting by \n or ,.
Thanks
I'm taking Software Testing because I'm majoring in CS. The professor gave us the source code of a program made in Java to test it. I'm testing right now this method:
public static void createPanel(HttpServletRequest req, HttpServletResponse res, HttpSession hs) throws IOException
{
String panelName = req.getParameter("panelName");
String panelDescription = req.getParameter("panelDescription");
int employeeID = ((EmployeeProfile)hs.getAttribute("User Profile")).EmployeeID;
boolean result;
//Let's validate our fields
if(panelName.equals("") || panelDescription.equals(""))
result = false;
else
result = DBManager.createPanel(panelName, panelDescription, employeeID);
b = result;
//We'll now display a message indicating the success of the operation to the user
if(result)
res.sendRedirect("messagePage?messageCode=Panel has been successfully created.");
else
res.sendRedirect("errorPage?errorCode=There was an error creating the panel. Please try again.");
}
I'm using Eclipse with JUnit and mockito to test all the methods including this one. For this specific method, I want to check if the program redirects to one location or another, but I don't know how to do it. Do you have any idea? Thanks.
You can actually achieve it easily with Mockito and ArgumentCaptor:
#RunWith(MockitoJUnitRunner.class)
public class MyTest {
#Mock
private HttpServletResponse response
...
#Test
public void testCreatePanelRedirection(){
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
YourClass.createPanel(request, response, session);
verify(response).sendRedirect(captor.capture());
assertEquals("ExpectedURL", captor.getValue());
}
}