Access Wicket page object outside of wicket component hierarchy - java

I have pojo classes that handle my backend connections. I want to encapsulate my (backend) error handling in these classes by catching backend exceptions inside.
Is there any way to access the current wicket page (or any component for that matter) to enable me to give feedback to the user from outside the wicket component hierarchy?
class MyService {
...
public void doBackEndThing(){
try {
backEndService.doRemoteCall();
} catch (BackendException e) {
//we're not inside the component hierarchy! so no getPage() available
WebPage page = getCurrentPage();
page.error("Backend is currently not available");
}
}
I've tried the PageManager, but I have no idea how to retrieve the correct version and so I do not know if would work at all:
int version = ?;
WebPage page = (WebPage )Session.get().getPageManager().getPage(version);

There isn't a nice way and it doesn't seem to be a good idea to do this. Your frontend should call your backend not the other way. So the easiest way to do this would be to store the errors inside your service and have your page get these.
class MyService {
private String error;
public void doBackEndThing(){
try {
backEndService.doRemoteCall();
} catch (BackendException e) {
error ="Backend is currently not available";
}
}
}
and
class MyPage extends WebPage {
private MySerivce service;
public void doSomethingFrontendy() {
error = service.getError();
}
}
or you could return an error from your backend method or throw an Exception and handle this in your WebPage or use IRequestCycleListener#onException() like #svenmeier pointed out.

IRequestCycleListener#onException() is a better place for this - you can get access to the current page via RequestCycle#getActiveRequestHandler().

Related

Using OTEL Java agent, how to create a new Context without using #WithSpan

The opentelemetry-javaagent-all agent (versions 0.17.0 and 1.0.1) has been the starting point for adding trace information to my Java application. Auto-instrumentation works great.
Some of my application cannot be auto-instrumented. For this part of the application, I began by adding #WithSpan annotations to interesting spots in the code.
I now reach the limits of what seems possible with simple #WithSpan annotations. However, the framework underlying my app allows me to register callbacks to be invoked at certain points -- e.g. I can provide handlers that are notified when a client connects / disconnects.
What I think I need is to start a new Span when Foo.onConnect() is called, and set it be the parent for the Spans that correspond to each request.
public class Foo {
void onConnect() {
// called when a client connects to my app
// Here I want to create a Span that will be the parent of the Span created in
// Foo.processEachRequest().
}
#WithSpan
public void processEachRequest() {
// works, but since it is called for each request... each span is in a separate Trace
}
void onDisconnect() {
// called when the client disconnects from my app
// Here I can end the parent Span.
}
}
Other ideas - that didn't work out:
1 - The obvious solution would be to add #WithSpan annotations to the underlying framework. For various reasons, this is not going to be a practical way forward.
2 - Next choice might be to search for a way to tell the javaagent about methods in my underlying framework. (The New Relic agent can do something like this.) That doesn't seem to be a feature of the open-telemetry agent, today anyway.
So, I'm left with looking for a way to do this using the callbacks, as above.
Is there a way to do this?
That should be possible by manually instrumenting your code. You would use the Tracer interface of OpenTelemetry, as described in the OpenTelemetry Java docs.
This should give you a general idea:
public class Foo {
private Span parentSpan; // you might need a Map/List/Stack here
void onConnect() {
Tracer tracer =
openTelemetry.getTracer("instrumentation-library-name", "1.0.0");
Span span = tracer.spanBuilder("my span").startSpan();
this.parentSpan = span; // might need to store span per request/client/connection-id
}
public void processEachRequest() {
final Span parent = this.lookupParentSpan();
if (parent != null) {
try (Scope scope = span.makeCurrent()) {
yourLogic();
} catch (Throwable t) {
span.setStatus(StatusCode.ERROR, "error message");
throw t;
}
} else {
yourLogic();
}
}
void onDisconnect() {
final Span parent = this.lookupParentSpan();
if (parent != null) {
parent.end();
}
}
private Span lookupParentSpan() {
// you probably want to lookup the span by client or connection id from a (weak) map
return this.parentSpan;
}
}
NB: You must guarantee that a span is always ended and does not leak. Make sure to properly scope your spans and eventually call Span#end().

Handling errors coming from gateway implementation in the use case - Clean Architecture

how can I handle exceptions coming from the gateway implementation when we are building software using the Onion Architecture?
To clarify, I've created an example using Java and SpringBoot:
#Component
#AllArgsConstructor
public class SaveAddressUseCase{
private final GetCustomerGateway getCustomerGateway;
public void execute(AddressDomain address, Long customerId){
try{
//validates the customerId supplied and returns the customer from an external service.
CustomerDomain customer = getCustomerGateway.execute(customerId);
address.setCustomer(customer);
//saves the address
}catch(CustomerNotFoundException ex) {
AddressErrorDomain addressErrorDomain = new AddressErrorDomain();
//saves the address in a error table with httpStatus 404
} catch (InternalErrorException ex) {
AddressErrorDomain addressErrorDomain = new AddressErrorDomain();
//save the address in a error table with httpStatus 500
}
}
}
This is a simple useCase that will save an address but first, it needs to get the customer of this address from an external service. If the customer is not found, I need to save the address in an error table to processes it later. The same goes if this external service is down, but it's important to differentiate between these two errors and I can handle this problem using the HttpStatus returned from my API call.
public interface GetCustomerGateway {
CustomerDomain execute(Long customerId);
}
#Component
#AllArgsConstructor
public class GetCustomerGatewayImpl implements GetCustomerGateway {
private final CustomerApi customerApi; //Feign interface to call an external service
public CustomerDomain execute(Long customerId){
try{
return customerApi.getCustomerById(customerId);
}catch(FeignException ex){
if (ex.status() == HttpStatus.NOT_FOUND.value()) {
throw new CustomerNotFoundException();
} else {
throw new InternalErrorException();
}
}
}
}
Lastly, this is my gateway implementation that just makes a call to this external service using a simple Feign interface and throws two custom exceptions that I extended from RuntimeException.
Question: Catching these two exceptions in the usecase I'm not dealing with details that only the gateway must know? Or even worse, I'm not using exceptions to control the flow of my application? How can I handle the errors coming from the Gateway implementation in a better way than I did in my example?
Obs: In this example, it's important to save the address in error table to not ruins the user experience in the client-side, and I also need to differentiate between these errors.
Thanks in advance!
Consider using #ControllerAdvice for this to keep the controller clean and focused
#ControllerAdvice
#Slf4j
public class RestExceptionHandler {
//Magic happens here
}
Inside RestExceptionHandler, you can catch all feign exceptions like this and handle them however you want
#ResponseBody
#ExceptionHandler(Throwable.class)
public final ResponseEntity<?> handleFeignExceptions(Exception ex, WebRequest request) {
if (ex instanceof FeignException) {
return handle((FeignException) ex);// define your custom handle method
}
}

JavaEE Globally Catch Runtime exception

I want to "globally" catch a Runtime exception, now this sounds silly right but let me explain.
I have created a interceptor that I use on all my ejbs which require authorization to use, this interceptor is called every time a method is called.
See here the code:
#Secure
#Interceptor
public class SecurityInterceptor {
#EJB
private SessionManager sessionManager;
#AroundInvoke
private Object securityCheck(InvocationContext ctx) throws Exception {
System.out.println("hello");
List<UserGroup> allowedRoles = (List<UserGroup>) ctx.getContextData().get("rolesAllowed");
sessionManager.isAuthorized(allowedRoles);
return ctx.proceed();
}
}
Now I don't want in my Named Bean to surround the body of every method that uses one of these secured beans with a try and catch block, like this:
public List<Contracts> getContracts() {
List<Contracts> contracts = new ArrayList<>();
try {
contracts = contractEntityManager.getAll();
} catch (EJBTransactionRolledbackException e) {
Throwable throwable = ExceptionUtils.getRootCause(e);
if (throwable instanceof NotAuthenticatedException) {
System.out.println("Not Authenticated");
}
else if (throwable instanceof UnAuthorizedException) {
System.out.println("Not Authorized");
}
}
return contracts;
}
So is there some way to globally catch a runtime exception and the redirect the user to the login page if he is unauthenticated and to a error page when he is unauthorized.
Maybe my design is just generally bad and I would need to complety rethink this idea.
Please let me know.
Thank you
So, in the end, it is the in the web tier that you want to catch the exceptions. This is easy:
If you are only on servlets, specify the error-page element in web.xml for each exception you wish to handle, e.g. as follows:
<error-page>
<exception-type>fully.quallified.NotAuthenticatedException</exception-type>
<location>/where/to/redirect/eg/login</location>
</error-page>
You declare the exception you want to handle globally and the URL you want to handle it, it may be a servlet, a JSP or any other resource.
JAX-RS offers a similar mechanism with the javax.ws.rs.ext.ExceptionMapper:
#Provider
public class NotAuthenticatedExceptionMapper implements ExceptionMapper<NotAuthenticatedException> {
...
}

Wicket setPageExpiredErrorPage only for specific page?

Is there any way to do that?
I heard something about implemented RequestCycle, how to acomplish that?
Tried How can I get the responsePage from a RequestCycle in Wicket 1.5? this, but doesnt work.
The reason why you get a PageExpiredException in Wicket is because Wicket is unable to find the page. There is no way of determining the type of the page that is no longer available, because, well, the page actually is no longer there. It ceased to exist, met its maker, bereft of life, rests in peace, its lifecycle are now 'istory, kicked the bucket. It is an ex-page.
So Wicket's only recourse is to serve the PageExpiredException, and there is no way (in Wicket itself) to retrieve the page that was attempted to resurrect.
Now what you can try to do is to store the class of the last rendered page in the session, and use that in your RequestCycleListener implementation of onException() and return the appropriate request handler. In code:
#Override
public void onRequestHandlerExecuted(RequestCycle cycle, IRequestHandler handler) {
Class<? extends Page> p = null;
if(handler instanceof IPageRequestHandler)
p = ((IPageRequestHandler)handler).getPageClass();
else if(handler instanceof IComponentRequestHandler)
p = ((IComponentRequestHandler)handler).getComponent().getPage().getClass();
MySession.get().setLastPageClass(p);
}
#Override
public IRequestHandler onException(RequestCycle cycle, Exception ex) {
Class<? extends Page> pageClass MySession.get().getLastPageClass();
... return some handler based on your logic
}
You might want to check for more IRequestHandler implementations in onRequestHandlerExecuted.
If I understand correctly you want to redirect user only if pageExpired happened from specific page? You can try something like this in you implementation of Application:
getRequestCycleListeners().add(new AbstractRequestCycleListener() {
#Override
public IRequestHandler onException(RequestCycle cycle, Exception e) {
if(e.getClass().equals(PageExpiredException.class)) {
//check if url in request responds to correct mounted page type
if(isPageUrl(cycle.getRequest().getUrl()))) {
return new RenderPageRequestHandler(new PageProvider(MyPage.class));
} else {
return super.onException(cycle, e);
}
} else {
return super.onException(cycle, e);
}
}
}
This assumes few things - that the page at which you got the exception has been mounted, and that you will be able to parse request url to be sure it is it.
I haven't tested it but we are doing something similar.

Does this program introduce a parallel execution?

Here is a simple server application using Bonjour and written in Java. The main part of the code is given here:
public class ServiceAnnouncer implements IServiceAnnouncer, RegisterListener {
private DNSSDRegistration serviceRecord;
private boolean registered;
public boolean isRegistered(){
return registered;
}
public void registerService() {
try {
serviceRecord = DNSSD.register(0,0,null,"_killerapp._tcp", null,null,1234,null,this);
} catch (DNSSDException e) {
// error handling here
}
}
public void unregisterService(){
serviceRecord.stop();
registered = false;
}
public void serviceRegistered(DNSSDRegistration registration, int flags,String serviceName, String regType, String domain){
registered = true;
}
public void operationFailed(DNSSDService registration, int error){
// do error handling here if you want to.
}
}
I understand it in the following way. We can try to register a service calling "registerService" method which, in its turn, calls "DNSSD.register" method. "DNSSD.register" try to register the service and, in general case, it can end up with two results: service was "successfully registered" and "registration failed". In both cases "DNSSD.register" calls a corresponding method (either "serviceRegistered" or "operationFailed") of the object which was given to the DNSSD.register as the last argument. And programmer decides what to put into "serviceRegistered" and "operationFailed". It is clear.
But should I try to register a service from the "operationFailed"? I am afraid that in this way my application will try to register the service too frequently. Should I put some "sleep" or "pause" into "operationFailed"? But in any case, it seems to me, that when the application is unable to register a service it will be also unable to do something else (for example to take care of GUI). Or may be DNSSD.register introduce some kind of parallelism? I mean it starts a new thread but that if I try to register service from "operation Failed", I could generate a huge number of the threads. Can it happen? If it is the case, should it be a problem? And if it is the case, how can I resolve this problem?
Yes, callbacks from the DNSSD APIs can come asynchronously from another thread. This exerpt from the O'Reilly book on ZeroConf networking gives some useful information.
I'm not sure retrying the registration from your operationFailed callback is a good idea. At least without some understanding of why the registration failed, is simply retrying it with the same parameters going to make sense?

Categories

Resources