From the server Code (in an HttpServlet) I'm throwing an exception if the file is too large:
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
...
// Check if the blob has correct size, otherwise delete it
final BlobInfo blobInfo = new BlobInfoFactory().loadBlobInfo(blobKey);
long size = blobInfo.getSize();
if(size > 0 && size <= BasicConstants.maxImageSize){
res.sendRedirect("/download?blob-key=" + blobKey.getKeyString());
} else { // size not allowed
bs.delete(blobKey);
throw new RuntimeException(BasicConstants.fileTooLarge);
}
From the client code I'm missing to successfully catch the exception with this snippet:
try {
uploadForm.submit(); // send file to BlobStore, where the doPost method is executed
} catch (Exception ex) {
GWT.log(ex.toString());
}
However, from this other client code snippet I'm somehow detecting when the exception was thrown with an ugly workaround that I don't trust at all:
uploadForm.addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler() {
#Override
public void onSubmitComplete(SubmitCompleteEvent event) {
// This is what gets the result back - the content-type *must* be
// text-html
String imageUrl =event.getResults();
// This ugly workaround apparently manages to detect when the server threw the exception
if (imageUrl.length() == 0) { // file is too large
uploadFooter.setText(BasicConstants.fileTooLarge);
} else { // file was successfully uploaded
...
}
The Development Mode view in Eclipse reports an error of type "uncaught exception", which suggests that I'm really doing a bad job at detecting it.
Can anyone tell me how to properly catch the exception, and if the workaround I'm using makes any sense?
Thanks!
Your first attempt
try {
uploadForm.submit(); // send file to BlobStore, where the doPost method is executed
} catch (Exception ex) {
GWT.log(ex.toString());
}
doesn't work, because submit() doesn't wait until the browser receives the response (it's an asynchronous call).
uploadForm.addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler() {
#Override
public void onSubmitComplete(SubmitCompleteEvent event) {
...
Here you actually receive the response from the server. But it's a form submission, not a GWT-RPC call, so the result is just plain text, not GWT Java Objects.
When you throw a RuntimeException in a Servlet, the server will simply send a response with an error code (probably '500', but ideally use the "Network" tab in Firebug or Chrome Developer Tools to see the actual response and response code.) So in the success case you'll get the URL, otherwise the response is empty.
Possible solution
You can catch Exceptions on the server side, and send better descriptions explicitly:
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
try {
...
if (...) {
throw new MyTooLargeException();
} else {
...
res.getWriter().write("ok " + ...);
}
} catch (MyTooLargeException e) {
res.getWriter().write("upload_size_exceeded"); // just an example string
// (use your own)
res.sendError(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE);
}
}
Then, on the client, check for
"upload_size_exceeded".equals(event.getResults()).
Related
I have Jenkins plugin written in Java. I am capturing all the workflows of execution of plugin in a integer variable in three ways 0(2xx workflows), 1(4xx workflows), 2(5xx workflows) and sending them to SignalFX for metrics. Since this is not an API and errors will be mainly caught in try catch workflow.
I wanted to ask how to read error codes from exception class and categorize them in 2xx, 4xx or 5xx. Are there some rules which I can follow by?
try {
Thread.sleep(60 * 1000);
} catch (InterruptedException e) {
sendToSignalFX(0,data); // 0 means successful state
}
Some of the exceptions classes I will be using are -
Exception, IOException, InterruptedException, ParserConfigurationException, SAXException
I believe you may have to add a method to identify the failure reason from e.getMessage() for one OR have a custom exception to help with your case.
Also if it’s an HTTP request-related exception (from the error response code mentioned in the question details) or something, you may want to add a custom exception, instead of throwing the original exception. In the custom exception, you can add a custom field to get errorCode from the response code.
// MyCustomException.java
public class MyCustomException extends Exception {
String errorReason;
int errorCode;
public MyCustomException(Throwable throwable, String errorReason, int errorCode) {
super(errorReason, throwable);
this.errorReason = errorReason;
this.errorCode = errorCode;
}
}
And in your request handler code:
try {
// otherCode which might cause IOException
// ...
Response response = myHttpRequest();
if (!response.isSuccessful()) {
// identify the error code and set corresponding errorCode to MyCustomException. errorCode
int errorCode = 0;
// parse response.getStatusCode() or equivalent of the library and reassign the value of errorCode
throw new MyCustomException(e, e.getMessage(), errorCode);
}
// ...
// otherCode which might cause IOException
} catch (Exception | IOException e) {
throw new MyCustomException(e, e.getMessage(), 0);
}
I have a problem with obtaining the response from API connection, I used logcat(Log.wtf) testing it then found the logcat in the first class which in my ConnectAPI.java had received the data, but the logcat(Log.wtf) in the second class which in my main.java unable to obtain the response from the first class, please helping me figure it out what the wrong it is, many thanks!
first class(in ConnectAPI.java)
public static void A020 (final Context context, String Manual, final ZooCallback callback){
HttpUrl url = new HttpUrl.Builder()
.scheme(SCHEME)
.host(HOST)
.port(PORT)
.addPathSegments(A020_PATH)
.addQueryParameter("LId", PersonID.getID(context))
.addQueryParameter("Coordinates", getGPS(context))
.addQueryParameter("Manual", Manual)
.build();
Request request = new Request.Builder()
.url(url)
.build();
Log.d("A020 printing out the url", url.toString());
mClient.newCall(request).enqueue(new Callback() {
#Override
public void onResponse(Call call, Response response) throws IOException {
try {
Log.wtf("A020 print out in connectapi",response.toString());
if (response != null && response.isSuccessful()) {
String jsonData = response.body().string();
final JSONObject Jobject = new JSONObject(jsonData);
handler.post(new Runnable() {
#Override
public void run() {
callback.onSuccess(Jobject);
}
});
}
} catch (final JSONException e) {
handler.post(new Runnable() {
#Override
public void run() {
callback.onFail("exception", e.getMessage());
}
});
}
}
#Override
public void onFailure(Call call, final IOException e) {
handler.post(new Runnable() {
#Override
public void run() {
callback.onFail("onFailure", e.getMessage());
}
});
}
});
Second class(in main.java)
ConnectAPI.A020(context, Manual, new ZooCallback(){
#Override
public void onSuccess(JSONArray response){
super.onSuccess(response);
try{
Log.wtf("A020 printing the response in mainjava", response.toString());
}catch(JSONException e){
Log.d("probleminA020", e.getMessage());
}catch(Exception e){
Log.d("probleminA020", e.getMessage());
}
}
public void onFail(String title, String error){
super.onFail(title, error);
Log.d(TAG, error);
}
});
What a Terrible Failure: Report a condition that should never happen. The error will always be logged at level ASSERT with the call stack. Depending on system configuration, a report may be added to the DropBoxManager and/or the process may be terminated immediately with an error dialog.
That is the documentation behind Log.wtf. When you use Log.wtf, there is a chance it throws an error. In which case it is caught by the try-catch you have. Don't use Log.wtf for debug, as this can crash your app.
Use Log.d (or Log.d or whatever you feel like) but not under any circumstance use Log.wtf for debug.
Replace Log.wtf with a different Log call (I recommend Log.d) and try again.
What is most likely happening is that Log.wtf throws an exception. This exception is then caught by the handy try-catch you have there. The code then prints out the error message instead. The reason it isn't printing is because it also throws an exception which you then aren't printing out fully, which explains why you don't know what is causing it
And for future purposes, when printing a stacktrace, use e.printStackTrace as it prints the entire stacktrace and not just the error message.
Another error you are facing is an issue related to your tag length. If oyu target API 24 or above, there is a 23 char limit:
IllegalArgumentException is thrown if the tag.length() > 23 for Nougat (7.0) releases (API <= 23) and prior, there is no tag limit of concern after this API level.
If you don't target API 24 or above, ignore this part.
If you do target API 24 or above, you have to shorten the tag to 23 chars or less. It is generally a good idea to keep the tag short, API 24+ will crash the app if it isn't
I am creating a very basic webserver using netty and java. I will have basic functionality. It's main responsibilities would be to serve responses for API calls done from a client (e.g a browser, or a console app I am building) in JSON form or send a zip file. For that reason I have created the HttpServerHanddler class which is responsible for getting the request, parsing it to find the command and call the appropriate api call.It extends SimpleChannelInboundHandler
and overrides the following functions;
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
LOG.debug("channelActive");
}
#Override
public void channelReadComplete(ChannelHandlerContext ctx) {
LOG.debug("In channelComplete()");
ctx.flush();
}
#Override
public void channelRead0(ChannelHandlerContext ctx, Object msg)
throws IOException {
ctx = processMessage(ctx, msg);
if (!HttpHeaders.isKeepAlive(request)) {
// If keep-alive is off, close the connection once the content is
// fully written.
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(
ChannelFutureListener.CLOSE);
}
}
private ChannelHandlerContext processMessage(ChannelHandlerContext ctx, Object msg){
if (msg instanceof HttpRequest) {
HttpRequest request = this.request = (HttpRequest) msg;
if (HttpHeaders.is100ContinueExpected(request)) {
send100Continue(ctx);
}
//parse message to find command, parameters and cookies
ctx = executeCommand(command, parameters, cookies)
}
if (msg instanceof LastHttpContent) {
LOG.debug("msg is of LastHttpContent");
if (!HttpHeaders.isKeepAlive(request)) {
// If keep-alive is off, close the connection once the content is
// fully written.
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(
ChannelFutureListener.CLOSE);
}
}
return ctx;
}
private ChanndelHandlerContext executeCommand(String command, HashMap<String, List<String>>> parameters, Set<Cookie> cookies>){
//switch case to see which command has to be invoked
switch(command){
//many cases
case "/report":
ctx = myApi.getReport(parameters, cookies); //This is a member var of ServerHandler
break;
//many more cases
}
return ctx;
}
In my Api class that has the getReport function.
getReport
public ChannelHandlerContext getReportFile(Map<String, List<String>> parameters,
Set<Cookie> cookies) {
//some initiliazations. Actual file handing happens bellow
File file = new File(fixedReportPath);
RandomAccessFile raf = null;
long fileLength = 0L;
try {
raf = new RandomAccessFile(file, "r");
fileLength = raf.length();
LOG.debug("creating response for file");
this.response = Response.createFileResponse(fileLength);
this.ctx.write(response);
this.ctx.write(new HttpChunkedInput(new ChunkedFile(raf, 0,
fileLength,
8192)),
this.ctx.newProgressivePromise());
} catch (FileNotFoundException fnfe) {
LOG.debug("File was not found", fnfe);
this.response = Response.createStringResponse("failure");
this.ctx.write(response);
} catch (IOException ioe) {
LOG.debug("Error getting file size", ioe);
this.response = Response.createStringResponse("failure");
this.ctx.write(response);
} finally {
try {
raf.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return this.ctx;
}
Response class is responsible for handling various types of response creations (JsonString JsonArray JsonInteger File, etc)
public static FullHttpResponse createFileResponse(long fileLength) {
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
HttpHeaders.setContentLength(response, fileLength);
response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "application/octet-stream");
return response;
}
My Api works great for my Json responses(easier to achieve) but It won't work well with my json responses, but not with my file response. When making a request from e.g chrome it only hangs and does not download the file. Should I do something else when downloading a file using netty? I know its not the best wittern code, I still think I have some bits and pieces missing from totally understanding the code, but I would like your advice on how to handle download on my code. For my code I took under consideration this and this
First, some remarks on your code...
Instead of returning ctx, I would prefer to return the last Future for the last command, such that your last event (no keep alive on) could use it directly.
public void channelRead0(ChannelHandlerContext ctx, Object msg)
throws IOException {
ChannelFuture future = processMessage(ctx, msg);
if (future != null && !HttpHeaders.isKeepAlive(request)) {
// If keep-alive is off, close the connection once the content is
// fully written.
future.addListener(ChannelFutureListener.CLOSE);
}
}
Doing this way will allow to directly close without having any "pseudo" send, even empty.
Important: Note that in Http, the response is managed such that there are chunk send for all data after the first HttpResponse item, until the last one which is empty (LastHttpContent). Sending another empty one (Empty chunk but not LastHttpContent) could break the internal logic.
Moreover, you're doing the work twice (once in read0, once in processMessage), which could lead to some issues perhaps.
Also, since you check for KeepAlive, you should ensure to set it back in the response:
if (HttpHeaders.isKeepAlive(request)) {
response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
}
On your send, you have 2 choices (depending on the usage of SSL or not): you've selected only the second one, which is more general, so of course valid in all cases but less efficient.
// Write the content.
ChannelFuture sendFileFuture;
ChannelFuture lastContentFuture;
if (ctx.pipeline().get(SslHandler.class) == null) {
sendFileFuture =
ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise());
// Write the end marker.
lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); // <= last writeAndFlush
} else {
sendFileFuture =
ctx.writeAndFlush(new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)),
ctx.newProgressivePromise()); // <= last writeAndFlush
// HttpChunkedInput will write the end marker (LastHttpContent) for us.
lastContentFuture = sendFileFuture;
}
This is this lastContentFuture that you can get back to the caller to check the KeepAlive.
Note however that you didn't include a single flush there (except with your EMPTY_BUFFER but which can be the main reason of your issue there!), contrary to the example (from which I copied the source).
Note that both use a writeAndFlush for the last call (or the unique one).
I have written a huge Web-Application and 'forgot' to include logging (I only print the errors with the standard e.printStackTrace() method).
My question is, if there is any method to auto-log (getLogger.LOG(SEVERE,"...")) any thrown exception?
maybe with a custom exception-factory like in exceptionFactory JSF?
I want to log every thrown exception with my logger, e.g. before the program enters the catch-block, the exception has to be logged already:
try{
...
} catch(Exception1 e){
//Exception must have been already logged here (without adding getLogger().LOG(...) every time)
System.out.println(e.printStackTrace());
} catch(Exception2 e){
//Exception must have been already logged here (without adding getLogger().LOG(...) every time)
System.out.println(e.printStackTrace());
}
Take a look at aspect oriented programming which can insert logging code at runtime for your favorite logging framework. The JDK includes the java.lang.instrument package which can insert bytecodes during classloading to perform your logging.
Otherwise, you can install a servlet Filter as the top most filter in the call chain which will catch most of your exceptions.
public class LogFilter implements javax.servlet.Filter {
private static final String CLASS_NAME = LogFilter.class.getName();
private static final Logger logger = Logger.getLogger(CLASS_NAME);
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
logger.entering(CLASS_NAME, "doFilter", new Object[]{request, response});
try {
chain.doFilter(request, response);
} catch (IOException | ServletException | RuntimeException | Error ioe) {
logger.log(Level.SEVERE, "", ioe);
throw ioe; //Keep forwarding.
} catch (Throwable t) {
logger.log(Level.SEVERE, "", t);
throw new ServletException(t);
}
logger.exiting(CLASS_NAME, "doFilter");
}
#Override
public void destroy() {
}
}
You can set uncaught exception handler for main thread and every other you create using Thread.setUncaughtExceptionHandler() method and do all the required logging there.
I am now also in front of new larger project and interested in elimination of not necessary code to be produced. First I wanted to log every entry and exit from method including input and output data. In my case of event driven architecture I am pushing these data to elastic and analyse continuously method processing timeouts, that is lot of code lines. So I handled this with AspectJ. Very nice example of this is here:
http://www.baeldung.com/spring-performance-logging
Same applies for auto Error logging, here is dummy example which I will extend to work with slf4j, but these are details:
public aspect ExceptionLoggingAspect {
private Log log = LogFactory.getLog(this.getClass());
private Map loggedThrowables = new WeakHashMap();
public pointcut scope(): within(nl.boplicity..*);
after() throwing(Throwable t): scope() {
logThrowable(t, thisJoinPointStaticPart,
thisEnclosingJoinPointStaticPart);
}
before (Throwable t): handler(Exception+) && args(t) && scope() {
logThrowable(t, thisJoinPointStaticPart,
thisEnclosingJoinPointStaticPart);
}
protected synchronized void logThrowable(Throwable t, StaticPart location,
StaticPart enclosing) {
if (!loggedThrowables.containsKey(t)) {
loggedThrowables.put(t, null);
Signature signature = location.getSignature();
String source = signature.getDeclaringTypeName() + ":" +
(enclosing.getSourceLocation().getLine());
log.error("(a) " + source + " - " + t.toString(), t);
}
}
}
I would be happy to hear what else is good example of boiler plate code reduction. I of course use Loombok which does superior task...
NOTE: do not reinvent wheel, so look here as other people collected usefull AOP to be reused in your project out of the box :-)) open source is great community: https://github.com/jcabi/jcabi-aspects
if i want to delete welcome.html file how to delete it using http doDelete() methode how to do it i am new to java so plz help me
public void doDelete(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
boolean success = false;
File file = null;
try {
file = searchFile(request);
} catch (Exception ex) {
java.util.logging.Logger.getLogger(Request.class.getName()).
log(java.util.logging.Level.SEVERE, null, ex);
}
if (!file.exists()) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
} else {
success = file.delete(); // actual delete operation
}
if (success) {
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}
}
private String searchFile(HttpServletRequest req) throws Exception {
String fileName = req.getPathInfo();
fileName = fileName.substring(1);
return fileName;
}
While we wait for you to explain how your code "doesn't work" ... I should point out that if this code did work, it would be extremely dangerous.
Your code makes no attempt to check that the user (i.e. the guy sending the request) should be allowed to delete the file, or what the user is attempting to delete. If some bad guy sent you a DELETE request with ".."'s in it, they could probably trick your web server into attempting to delete any file in the file system!!! (Hopefully you never run your web servers as "root" ...)
UPDATE: The answer to your Question is simple. Change
file = searchFile(request);
to
file = new File(searchFile(request));
But that is the least of your problems!