I have a newly coded GWT/GAE app that uses RequestFactory and Editors on the client and a custom Objectify DAO Service on the back.
The flush() then persist() paths work fine on success.
Client side JSR 303 works as well as can be expected too.
My question is how to trigger server warnings/errors and handle UI updates?
I am using Chandler's Generic DAO for Objectify 2 at
http://turbomanage.wordpress.com/2010/02/09/generic-dao-for-objectify-2/
my gwt activity is calling persist( myProxy ).fire( new Receiver<> )
my dao code is throwing IllegalArgumentException and other RuntimeExceptions for business logic situations like "Duplicate email address found - want to login instead?"
Receiver<>.onSuccess() works fine to track a successful outcome.
neither Receiver<>.onFailure() nor Receiver<>.onViolation() report the RuntimeExceptions.
( Correction: onFailure() is being called for server-side exceptions)
Is there a better way to do this?
What exceptions should the DAO throw such that onViolation() or onFailure() report errors?
How should the editor(s) handle and recover from the exception?
I've found the most versatile command sequence to be
void start() {
// Either get p
context1.get(..).to( new Receiver<P> { onSuccess(P resp){p = resp;} ... }).fire();
// OR create p
p = context2.create( P.class );
// Then save p
req = context2.persist(p).to( new Receiver<P>{ /* note do not use context1 */
onViolation(...) { /*JSR 303 handler*/ };
onFailure( error ) { /* handle */ error.getMessage() };
onSuccess(X x) { /* whatever persist() returns handler */ }; } );
// drive editor with p
driver.edit( p, req);
}
....
void onSave() {
// editor
ctxt = driver.flush() /* note ctxt == context2 */
if ( driver.hasErrors() ) { /*JSR 303 handler*/};
// RF
ctxt.fire();
}
Based on the conversation excerpt below at http://groups.google.com/group/google-web-toolkit/browse_thread/thread/da863606b3893132/96956661c53e1064?hl=en
Thomas Broyer
onFailure should containg the getMessage() of the
exception you threw on the server
side.
You can tweak it by providing your own
ExceptionHandler to the
RequestFactoryServlet (extend it and
use its constructor taking an
ExceptionHandler).
onViolation will only be called if
your entities do not pass JSR-303 Bean
Validation, which is checked before
calling any service method.
If you want to
"catch" the failure in clidnt code,
you have to add a Receiver for the
persist() service method:
context.persist(p).to(new Receiver…
Related
I use an external rest api in my spring application, I can send json post requests to create objects but when a field is incorrect or if there is a duplicate it returns a 400 bad request error, and a body saying what the problem is.
I use Spring 5 with #PostExchange in the following code:
This is used to point spring into the right direction of the external api
public interface HardwareClient {
#PostExchange("/assetmgmt/assets/templateId/C04DBCC3-5FD3-45A2-BD34-8A84CE2EAC20")
String addMonitor(#RequestBody Monitor monitor);
}
This is the helper that is autowired into the class where I have the data that needs to be sent.
#Component
public class HardwareHelper {
private Logger logger = Logger.getLogger(getClass().getName());
#Autowired
HardwareClient hardwareClient;
#Async
public Future<String> addMonitor(MonitorForm monitorForm){
try {
Monitor monitor = new Monitor(monitorForm.objectID(), monitorForm.model(), monitorForm.make(),monitorForm.serialNumber(), monitorForm.orderNumber(),monitorForm.budgetholder(),monitorForm.ownership());
hardwareClient.addMonitor(monitor);
return new AsyncResult<String>("Success");
} catch (Exception e){
logger.info("HardwareHelper.addMonitor error: " + e.getMessage());
//todo error handling
}
return null;
}
}
When an error occurs the logger will print the error but I need to be able to control what happens after based on the response. So I need to see the body of the post request that is returned after. If everything goes well an ID is returned that I can read by printing the results of the addMonitor() method, but this is obviously not possible when it throws an exception as it skips to the catch part. How do I scan the request body when an error is thrown and handle this appropriately
I just started with Lagom & Akka. I am following the design decribed in Domain Modelling with Akka Persistence Typed
I am trying to create a brand new instance of an entity (EntityState). But the event is not getting persisted, and I am getting the following error:
00:54:27.862 [error] com.example.impl.entity.EntityClass [persistencePhase=running-cmd, akkaAddress=akka://XXX#127.0.0.1:60685, akkaSource=akka://XXX/system/sharding/StateClass/186/ID1, sourceActorSystem=XXX, persistenceId=StateClass|ID1] - Supervisor StopSupervisor saw failure: null
java.lang.NullPointerException: null
at akka.persistence.typed.javadsl.EventSourcedBehavior.$anonfun$apply$4(EventSourcedBehavior.scala:195)
at akka.persistence.typed.internal.Running$RunningState.applyEvent(Running.scala:78)
at akka.persistence.typed.internal.Running$HandlingCommands.applyEffects(Running.scala:153)
at akka.persistence.typed.internal.Running$HandlingCommands.onCommand(Running.scala:123)
at akka.persistence.typed.internal.Running$HandlingCommands.onMessage(Running.scala:105)
at akka.persistence.typed.internal.Running$HandlingCommands.onMessage(Running.scala:100)
at akka.actor.typed.scaladsl.AbstractBehavior.receive(AbstractBehavior.scala:83)
I have a Create command, which invokes onCreate(), and eventually attempts to persist an EntityCreated event.
Service Impl method
#Override
public ServiceCall<CreateMessage, StateView> createState(){
return message ->
entityRef(message.getName())
.<EntityClass.Accepted>ask(replyTo -> new EntityClass.Create(message, replyTo), askTimeout)
.thenApply(accepted -> toStateView(accepted.getSummary()));
}
Command handler:
private ReplyEffect<Event, StateClass> onCreate(StateClass state, Create cmd) {
return Effect()
.persist(new EntityCreated(cmd.getDetails().getName(), Instant.now()))
.thenReply(cmd.replyTo, e -> new Accepted(EntityClass.toSummary(e)));
}
I am able to confirm the following:
exception is thrown during persist()
the event is not present in Cassandra
Your help is appreciated. Thank you in advance!
It seems that the real cause for the exception was because I should have added logic for handling the event as follows:
in helloEvents(), I needed to add logic similar to the following:
if (eventAndOffset.first() instanceof HelloEvent.GreetingMessageChanged) {
HelloEvent.GreetingMessageChanged messageChanged = (HelloEvent.GreetingMessageChanged) eventAndOffset.first();
eventToPublish = new GreetingMessageChanged(messageChanged.getName(), messageChanged.getMessage());
}
In Addition, in the aggregate's eventHandler(), I needed to add logic similar to the following:
builder.forAnyState()
.onEvent(GreetingMessageChanged.class, (state, evt) ->
// We simply update the current state to use the greeting message from
// the event.
state.withMessage(evt.message)
);
In my application I have different layers like the rest layer, service layer and DB layer, according to business scenarios I am trowing different business exceptions from the service layer.
But now, I have to set different HTTP codes like 400, 403, 409, 412.. to REST responses.
How can I set different HTTP status codes based on different scenarios?
Which is the most feasible way like: aspect, exception mapper, or ....?
Since I can set HTTP status only once in rest layer (
referred this ), I am not able to map to different HTTP codes because my exception is from service layer.
My exception class looks like this:
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = 1L;
public BusinessException(ErrorEnumeration error) {
}
public BusinessException(Exception e, ErrorEnumeration error) {
}
}
and the exception will be thrown from the service like this:
throw new BusinessException(ErrorEnumeration.VALIDATION_FAILED);
Please help by suggesting a solution
You can use exceptions defined in jax-rs or you can use your own exceptions. Fist catch your business exceptions and convert them to jax-rs versions. For example, for 404 you can throw javax.ws.rs.NotFoundException.
You can also write your own exceptions by extending them from javax.ws.rs.ClientErrorException
Here is an example for 409-Conflict status exception
import javax.ws.rs.ClientErrorException;
import javax.ws.rs.core.Response;
public class ConflictException extends ClientErrorException{
public ConflictException(Response.Status status) {
super(Response.Status.CONFLICT); // 409
}
}
Update
Most simple and feasible way is catching your business exceptions and re-throw them with jax-rs exceptions.
try{
businessService.executeBusinessRule();
}catch (BusinessException e){
// It is better if your BusinessException has some child class to handle
if(e.getError() == ErrorEnumeration.VALIDATION_FAILED){
throw new BadRequestException();
}else{
throw new ConflictException();
}
}
If you are using spring you can always catch these exceptions using aop.
#Aspect
public class BusinessExceptionInterceptor{
#AfterThrowing(pointcut = "execution(* com.your.service.packge..* (..))", throwing = "e")
public void errorInterceptor(BusinessException e) {
// re-throw again...
}
Update 2
Also it is better to define a new exception instead of reusing same exception with different state. You can define a new ValidationException which extends from BusinessException like this.
public class ValidationException extends BusinessException{
public ValidationException() {
super(ErrorEnumeration.VALIDATION_FAILED);
}
}
By using this way you can still handle all the BusinessException but it is easier to identify or map them to Jax-rs exceptions.
I am trying to dispatch fault event in GraniteDS service
method call (Flex):
userService.addUser(user, null, function addUserFault(e:TideFaultEvent):void {
Alert.show(e.fault.faultString);
});
server method (Spring):
#Override
public User addUser(User user) throws Exception{
if(findUserByName(user.getUsername()) != null)
throw new Exception("Username Already Exist");
entityManager.persist(user);
return user;
}
But what i get is silence on client side and java.lang.NoSuchMethodException in server console.
How can i use default graniteds exception converter to deliver fault event to client (Flex)?
Solved. I dont know if it's a bug or not, but you cannot set result function to null and specify fault function only - this wont work. My call method should look like:
userService.addUser(user, function addUserResult(e:TideResultEvent){
// do nothing
}, function addUserFault(e:TideFaultEvent):void {
Alert.show(e.fault.faultString);
});
in this case java Exception in remote method will be send back to flex as TideFaultEvent.
Our application uses several back-end services and we maintain wrappers which contain the methods to make the actual service calls. If any exception occurs in any of those methods while invoking a service, we throw a custom exception encapsulating the original exception as shown below.
interface IServiceA {
public void submit(String user, String attributes);
}
public class ServiceAWrapper implements IserviceA {
private ActualService getActualService() {
.....
}
public void submit(String user, String attributes) {
try {
Request request = new Request();
request.setUser(user);
request.setAttributes(attributes);
getActualService().call(request);
} catch(ServiceException1 e) {
throw new MyException(e, reason1);
} catch(ServiceException2 e) {
throw new MyException(e, reason2);
}
}
}
I would like to know if there's any framework that would allow me to
capture (and probably log) all the
parameters passed to my wrapper
methods at run-time; if the methods
are called.
capture the actual exception
object(MyException instance in above
example), if any thrown; so that I
could append the passed parameters
to the object at run-time.
I am currently exploring AspectJ to see if it can address my requirements, but I am not sure if it can be used to capture the parameters passed to methods at runtime and also to capture exception objects, if any occur.
Thanks.
With AspectJ, you can use around advice to execute advice instead of the code at the join point. You can then execute the actual join-point from within the advice by calling proceed. This would allow you to capture the input parameters, log them, and proceed to call the actual method.
Within the same advice you could capture any logs throw from the method, and inspect or log them before passing it back up to higher levels.
Matt B's answer is right. Specifically, you can do something like this:
aspect MonitorServiceCalls {
private final Logger LOG = LoggerFactory.getLog("ServiceCallLog");
Object around() throws MyException: call(public * *(..) throws MyException)
&& target(IServiceA+) {
MethodSignature msig = (MethodSignature)thisJoinPoint;
String fullMethName = msig.getMethod().toString();
try {
Object result = proceed();
LOG.info("Successful call to {} with arguments {}",
fullMethName,
thisJoinPoint.getArgs());
return result;
} catch(MyException e) {
LOG.warn("MyException thrown from {}: {}", msig.getMethod(), e);
throw e;
}
}
}
AspectJ is the right option. You will be able to get hold of the parameters by way of a JoinPoint object that will be passed to your advise methods. You can also get hold of the exception either by implementing an after throwing advise or an around advise.