I'm having responder flow failing with IllegalStateException, however the initiating one fails with UnexpectedFlowEndException. Is it possible to somehow get the information about the original exception ?
only if you wrap the original exception in something that extends FlowException, you need something like this
#InitiatedBy(InitiatorFlow::class)
class ResponderFlow : FlowLogic<Unit>() {
#Suspendable
override fun call() {
try {
// Your logic
} catch(e : IllegalStateException) {
throw FlowException(e)
}
}
}
note that InitiatorFlow will receive a FlowException containing an IllegalStateException as its cause
Related
Using Retrofit2 (Ver: 2.3.0), OkHTTP3 (Ver: 3.9.0) with RxJava2 (Ver: 2.0.0)
Scenario of a rest api call
Observable<ServerResponse> backendService.isUserVerified("someuserName")
which returns a 200 Ok HTTP
Expected Success Response JSON POJO if user is verified
{
user: "someUserName",
isVerified: "yes"
}
Expected Success Response JSON POJO if user is not verified
{
user: "someUserName",
isVerified: "no"
}
Following is code I am trying to implement
backendService.isUserVerified("someuserName")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
//Want to add a flatmap (or some other operator)
.flatmap(new Function<ServerResponse>, ObservableSource<?>>(){
#Override
public ObservableSource<?> apply(ServerResponse serverResponse) throws Exception {
if(0 != serverResponse.getisVerified.compareToIgnoreCase("yes")) {
return Observable.error(new CustomException());
}
return //current observable.
}
.retryWhen(mRetryHandler)
.subscribeWith(observer);
The intent is to throw a custom exception if verified == no so that retryWhen() operator can pitch in to repeat the call chain, else want to proceed through the chain till subscribe().
Any pointers / help ?
You can just use doOnNext rather than flatmap:
backendService.isUserVerified("someuserName")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
//we can throw an exception if the user is not verified or keep the response as it is otherwise
.doOnNext(serverResponse -> {
if(0 != serverResponse.getisVerified.compareToIgnoreCase("yes"))
{
throw new CustomException();
}
})
.retryWhen(mRetryHandler)
.subscribeWith(observer);
The doOnNext operator just performs a function with the emitted item without changing it. You just want to throw an error in a specific case based on the item and otherwise not to change it so it's an appropriate operator to use. As you don't change threads before the doOnNext operator or after it, before using the item in the next operator you know it will throw the exception BEFORE continuing in case it should throw it.
Here's an example from the linked documentation of the operator:
Observable.just(1, 2, 3)
.doOnNext(new Action1<Integer>() {
#Override
public void call(Integer item) {
if( item > 1 ) {
throw new RuntimeException( "Item exceeds maximum value" );
}
}
}).subscribe(new Subscriber<Integer>() {
#Override
public void onNext(Integer item) {
System.out.println("Next: " + item);
}
#Override
public void onError(Throwable error) {
System.err.println("Error: " + error.getMessage());
}
#Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
});
[output:]
Next: 1
Error: Item exceeds maximum value
If you want to throw an error using Observable.error(new CustomException());, you don't need to make function to return a specific object for the error and another one for the expected answer, it's an exception and will go to onError() method. Your ObservableResource<?> must return your expected answer that is retrieved in onResponse() method from Subscriber. If you throw an error using Observable.error(), your chain will be broken and error will be go to onError().
Edit
You should use retry function, because will return you ServerResponse and you can check if is valid or not. Using retryWhen, you get only the error when something goes wrong. In your case, you don't get any error, you get the answer. In this case, you don't need that flatMap
.retry(new BiPredicate<ServerResponse, Throwable>() {
#Override
public boolean test(ServerResponse serverResponse, Throwable throwable) throws Exception {
return serverResponse.getisVerified.equals("no");
}
})
We are using spring and spring-security-3.2. Recently We are adding annotations #PreAuthorize to RestAPIs(earlier it was URL based).
#PreAuthorize("hasPermission('salesorder','ViewSalesOrder')")
#RequestMapping(value = "/restapi/salesorders/", method = RequestMethod.GET)
public ModelAndView getSalesOrders(){}
We already have Global exception handler which annotated with - #ControllerAdvice and custom PermissionEvaluator in place, everything works fine except the error message.
Lets say some user is accessing API At moment without having 'ViewSalesOrder' permission then spring by default throws the exception 'Access is denied',but didn't tell which permission is missing (Its our requirement to mention which permission is missing).
Is it possible to throw an exception which also include the permission name, so final error message should be look like "Access is denied, you need ViewSalesOrder permission"(here permission name should be from #PreAuthorize annotation)?
Please note that we have 100 such restAPI in place so generic solution will be highly appreciated.
There is no pretty way of achieving what you expect since PermissionEvaluator interface doesn't let you pass the missing permission along with the result of the evaluation.
In addition, AccessDecisionManager decides on the final authorization with respect to the votes of the AccessDecisionVoter instances, one of which is PreInvocationAuthorizationAdviceVoter which votes with respect to the evaluation of #PreAuthorize value.
Long story short, PreInvocationAuthorizationAdviceVoter votes against the request (giving the request –1 point) when your custom PermissionEvaluator returns false to hasPermission call. As you see there is no way to propagate the cause of the failure in this flow.
On the other hand, you may try some workarounds to achieve what you want. One way can be to throw an exception within your custom PermissionEvaluator when permission check fails. You can use this exception to propagate the missing permission to your global exception handler. There, you can pass the missing permission to your message descriptors as a parameter. Beware that this will halt execution process of AccessDecisionManager which means successive voters will not be executed (defaults are RoleVoter and AuthenticatedVoter). You should be careful if you choose to go down this path.
Another safer but clumsier way can be to implement a custom AccessDeniedHandler and customize the error message before responding with 403. AccessDeniedHandler provides you current HttpServletRequest which can be used to retrieve the request URI. However, bad news in this case is, you need a URI to permission mapping in order to locate the missing permission.
I have implemented the second possible solution mentioned by Mert Z. My solution works only for #PreAuthorize annotations used in the API layer (e.g. with #RequestMapping). I have registered a custom AccessDeniedHandler bean in which I get the value of the #PreAuthorize annotation of the forbidden API method and fills it into error message.
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
private DispatcherServlet dispatcherServlet;
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException,
ServletException {
if (!response.isCommitted()) {
List<HandlerMapping> handlerMappings = dispatcherServlet.getHandlerMappings();
if (handlerMappings != null) {
HandlerExecutionChain handler = null;
for (HandlerMapping handlerMapping : handlerMappings) {
try {
handler = handlerMapping.getHandler(request);
} catch (Exception e) {}
if (handler != null)
break;
}
if (handler != null && handler.getHandler() instanceof HandlerMethod) {
HandlerMethod method = (HandlerMethod) handler.getHandler();
PreAuthorize methodAnnotation = method.getMethodAnnotation(PreAuthorize.class);
if (methodAnnotation != null) {
response.sendError(HttpStatus.FORBIDDEN.value(),
"Authorization condition not met: " + methodAnnotation.value());
return;
}
}
}
response.sendError(HttpStatus.FORBIDDEN.value(),
HttpStatus.FORBIDDEN.getReasonPhrase());
}
}
#Inject
public void setDispatcherServlet(DispatcherServlet dispatcherServlet) {
this.dispatcherServlet = dispatcherServlet;
}
}
The handler is registered in WebSecurityConfigurerAdapter:
#EnableGlobalMethodSecurity(jsr250Enabled = true, prePostEnabled = true)
#EnableWebSecurity
public abstract class BaseSecurityInitializer extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
...
http.exceptionHandling().accessDeniedHandler(accessDeniedHandler());
...
}
#Bean
public AccessDeniedHandler accessDeniedHandler() {
return new CustomAccessDeniedHandler();
}
}
Beware that if there is also a global resource exception handler with #ControllerAdvice the CustomAccessDeniedHandler won't be executed. I solved this by rethrowing the exception in the global handler (as advised here https://github.com/spring-projects/spring-security/issues/6908):
#ControllerAdvice
public class ResourceExceptionHandler {
#ExceptionHandler(AccessDeniedException.class)
public ResponseEntity accessDeniedException(AccessDeniedException e) throws AccessDeniedException {
log.info(e.toString());
throw e;
}
}
You can throw an org.springframework.security.access.AccessDeniedException from a method that was called inside an EL-Expression:
#PreAuthorize("#myBean.myMethod(#myRequestParameter)")
Ideally, the #PreAuthorize annotation should be supporting String message(); in addition to the SpEl value. But, for whatever reason, it does not. Most of the suggestions here seem unnecessarily cumbersome and elaborate. As #lathspell has suggested, the simplest way to provide your own error message - along with any custom access validation logic - would be to add a simple method that performs the check and throws the AccessDeniedException in case the check fails, and then reference that method in the SpEl expression. Here's an example:
#RestController
#RequiredArgsConstructor // if you use lombok
public class OrderController {
private final OrderService orderService;
...
#GetMapping(value = "/salesorders", produces = MediaType.APPLICATION_JSON_VALUE)
#PreAuthorize("#orderController.hasPermissionToSeeOrders(#someArgOfThisMethod)")
public Page<OrderDto> getSalesOrders(
// someArgOfThisMethod here, perhaps HttpRequest, #PathVariable, #RequestParam, etc.
int pageIndex, int pageSize, String sortBy, String sortOrder) {
Pageable pageRequest = PageRequest.of(pageIndex, pageSize, Sort.Direction.fromString(sortOrder), sortBy);
return ordersService.retrieveSalesOrders(..., pageRequest);
}
public static Boolean hasPermissionToSeeOrders(SomeArgOfTheTargetMethod argToEvaluate) {
//check eligibility to perform the operation based on some data from the incoming objects (argToEvaluate)
if (condition fails) {
throw new AccessDeniedException("Your message");
}
return true;
}
public class Foo<T> where T: Entity
{}
public class Foo1
: Foo<Telephone>
{
}
public class Foo2
: Foo<Home>
{
}
How do I send Foo1 to Foo2? I realize that the message is typed, and hence messages of the same type of recieved - but I need to message between the derived classes...
An example would be very much appreciated.
An alternative is to create your own class that contains the payload you wish to deliver (Foo1 or simply object). Then in Foo2, register to receive messages of the type of the class you just created.
This link explains how with a very easy to understand example.
MVVM Light Toolkit Soup To Nuts 3 - Jesse Liberty
the messaging in mvvmlight is in theory supposed to be fire and forget...the sender doesnt care who gets the message and the receiver doesnt care who sends the message, so long as its the right type that its listening for.
I have found through much trial and error that its much easier to craft your own messages than use the default provided by mvvm-light, they are a good starting point, but sometimes you will just findyourself jumping through hoops..
public class ExceptionMessage : GalaSoft.MvvmLight.Messaging.GenericMessage<System.Exception>
{
public ExceptionMessage(System.Exception content) : base(content) { }
public ExceptionMessage(object sender, System.Exception content) : base(sender, content) { }
public ExceptionMessage(object sender, object target, System.Exception content) : base(sender, target, content) { }
}
Receiver code:
Messenger.Default.Register<Core.Messaging.ExceptionMessage>(this, ex => ShowExceptionMessage(ex));
Sender Code:
public void LogException(Exception content)
{
_messenger.Send<Core.Messaging.ExceptionMessage>(new ExceptionMessage(content));
//GetBw().RunWorkerAsync(content);
WriteToDatabaseLog(content);
}
and yes this does break the suggestion in my first sentence, but in theory I could have several vms or view listening for exception messages.
Maybe another example to help you out... i hate the whole foo thing...its always confuses me...
This is in my core module:
public class SaveNotification<T> : GalaSoft.MvvmLight.Messaging.NotificationMessage<T> where T : GalaSoft.MvvmLight.ViewModelBase
{
public SaveNotification(T content, string notification) : base(content, notification) { }
public SaveNotification(object sender, T content, string notification) : base(sender, content, notification) { }
public SaveNotification(object sender, object target, T content, string notification) : base(sender, target, content, notification) { }
}
here is how I used it in my vm:
public void OnSubmitChanges(SubmitOperation so)
{
if (so.HasError)
{
Infrastructure.GetService<IExceptionLoggingInterface>().LogException(this, so.Error);
}
else
{
//Save Responses
_messenger.Send<Messages.NavigationRequest<SubClasses.URI.PageURI>>(GetNavRequest_HOME());
ClearQuestionaire(true);
_messenger.Send<WavelengthIS.Core.Messaging.SaveNotification<QuestionairreViewModel>>(GetSuccessfulSaveNotification());
}
Wait.End();
}
private WavelengthIS.Core.Messaging.SaveNotification<QuestionairreViewModel> GetSuccessfulSaveNotification()
{
return new WavelengthIS.Core.Messaging.SaveNotification<QuestionairreViewModel>(this, "Save Successfull");
}
Let's say I have the following interceptor in a SEAM app:
public class MyInterceptor {
#In
private Monitor myMonitor;
#AroundInvoke
public Object aroundInvoke(InvocationContext ctx) throws Exception {
try {
myMonitor.a();
return ctx.proceed();
}
finally {
myMonitor.b();
}
}
}
myMonitor.a() works (so Monitor is correctly injected), myMonitor.b() fails because Monitor is already null. Seam Doc says: "Injected values are disinjected (i.e., set to null) immediately after method completion and outjection."
Is that what is happening? Can I do something to tell SEAM to "not yet" "disinject" the component? I can of course also do something like XContext.get(..), but I'm wondering whether this is a bug or a mistake from my side. thanks!
Try this one instead
Object response = null;
try {
myMonitor.a();
response = ctx.proceed();
} finally {
myMonitor.b();
}
return response;
regards,
Avoid using injection.
Try working around this problem. I see you have some sort of monitoring going on. Look at this interceptor that captures the amount of time a method is executed in Seam components. Try modifying your code to match that.
It works great!
Here is the link
Seam is working as advertised.
You could just ignore the disinjection:
public class MyInterceptor {
private Monitor myMonitor;
#In
private void setMonitor(Monitor aMonitor) {
if (aMonitor != null) {
myMonitor = aMonitor;
}
}
#AroundInvoke
public Object aroundInvoke(InvocationContext ctx) throws Exception {
try {
myMonitor.a();
return ctx.proceed();
}
finally {
myMonitor.b();
myMonitor = null; //perform disinjection yourself
}
}
}
The caveat here is that Seam is disinjecting the reference for a reason. Seam wants to control the lifecycle and identity of "myMonitor" and by keeping a reference to it, you are not abiding by your contract with Seam. This could lead to unexpected behavior.
For instance, if myMonitor were for some reason in the Stateless scope, Seam might destroy it before ctx.proceed() returns, leaving you with a reference to a broken proxy. Best advice is to know the scope and lifecycle of what you are retaining since you are "living on the edge."
I want to intercept all method invocations to all seam components to see if that would help in logging exceptions. I was thinking that I could do this by getting the list of all components and registered interceptors and simply adding the one I want to that list.
Walter
Its better to use Seam's Exception handler.
This is how you can do it:
#Name("org.jboss.seam.exception.exceptions")
#Scope(ScopeType.APPLICATION)
#Install(precedence = Install.APPLICATION)
#BypassInterceptors
public class ExceptionHandler extends org.jboss.seam.exception.Exceptions {
public void handle(Exception e) throws Exception {
//Log your exception here if you want
Events.instance().raiseAsynchronousEvent("SomeListener",e.getMessage());
super.handle(e);
}
Try to override the default ExceptionFilter with your own at a higher precedence.
#Name("org.jboss.seam.web.exceptionFilter")
#Install(precedence = MOCK, classDependencies="javax.faces.context.FacesContext")
#BypassInterceptors
#Filter(within="org.jboss.seam.web.ajax4jsfFilter")
public class ExceptionFilter extends org.jboss.seam.web.ExceptionFilter
#Override
protected endWebRequestAfterException(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Exception e) {
// here you log exceptions
}
}