Refs #1004 Rework remote exception handling

This commit is contained in:
Konstantin Krivopustov 2011-11-21 12:04:21 +00:00
parent 2981589a05
commit 3e0ba255e9
48 changed files with 783 additions and 380 deletions

View File

@ -10,6 +10,7 @@
*/
package com.haulmont.cuba.core.sys;
import com.haulmont.cuba.core.global.RemoteException;
import com.haulmont.cuba.core.global.UserSessionSource;
import com.haulmont.cuba.security.global.UserSession;
import org.apache.commons.logging.Log;
@ -36,16 +37,17 @@ public class ServiceInterceptor
}
}
UserSession userSession = userSessionSource.getUserSession();
if (log.isTraceEnabled())
log.trace("Invoking: " + ctx.getSignature() + ", session=" + userSession);
try {
UserSession userSession = userSessionSource.getUserSession();
if (log.isTraceEnabled())
log.trace("Invoking: " + ctx.getSignature() + ", session=" + userSession);
Object res = ctx.proceed();
return res;
} catch (Throwable e) {
log.error("ServiceInterceptor caught exception: ", e);
throw e;
// Propagate the special exception to avoid serialization errors on remote clients
throw new RemoteException(e);
}
}
}

View File

@ -62,8 +62,6 @@ public class App implements ConnectionListener {
private DisabledGlassPane glassPane;
protected ExceptionHandlers exceptionHandlers;
protected DesktopTheme theme;
public static void main(final String[] args) {
@ -360,8 +358,6 @@ public class App implements ConnectionListener {
}
protected void initExceptionHandling() {
exceptionHandlers = new ExceptionHandlers();
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread thread, Throwable throwable) {
handleException(thread, throwable);
@ -373,25 +369,21 @@ public class App implements ConnectionListener {
public void handleException(Thread thread, Throwable throwable) {
log.error("Exception in thread " + thread, throwable);
exceptionHandlers.handle(thread, throwable);
ExceptionHandlers handlers = AppContext.getBean("cuba_ExceptionHandlers", ExceptionHandlers.class);
handlers.handle(thread, throwable);
}
/**
* Initializes exception handlers immediately after login and logout.
* Can be overridden in descendants to manipulate exception handlers programmatically.
* @param isConnected true after login, false after logout
*/
protected void initExceptionHandlers(boolean isConnected) {
ExceptionHandlers handlers = AppContext.getBean("cuba_ExceptionHandlers", ExceptionHandlers.class);
if (isConnected) {
exceptionHandlers.addHandler(new NoUserSessionHandler()); // must be the first handler
exceptionHandlers.addHandler(new SilentExceptionHandler());
exceptionHandlers.addHandler(new UniqueConstraintViolationHandler());
exceptionHandlers.addHandler(new AccessDeniedHandler());
exceptionHandlers.addHandler(new NoSuchScreenHandler());
exceptionHandlers.addHandler(new DeletePolicyHandler());
exceptionHandlers.addHandler(new NumericOverflowExceptionHandler());
exceptionHandlers.addHandler(new OptimisticExceptionHandler());
exceptionHandlers.addHandler(new JPAOptimisticExceptionHandler());
exceptionHandlers.addHandler(new ReportExceptionHandler());
exceptionHandlers.addHandler(new FileMissingExceptionHandler());
exceptionHandlers.addHandler(new EntityDeletedExceptionHandler());
handlers.createByConfiguration();
} else {
exceptionHandlers.getHandlers().clear();
handlers.removeAll();
}
}

View File

@ -7,36 +7,59 @@
package com.haulmont.cuba.desktop.exception;
import com.haulmont.cuba.core.global.MessageProvider;
import com.haulmont.cuba.core.global.RemoteException;
import com.haulmont.cuba.desktop.App;
import com.haulmont.cuba.gui.AppConfig;
import org.apache.commons.lang.exception.ExceptionUtils;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.List;
/**
* Base class for exception handlers determining their ability to handle an exception by its class name.
*
* <p>If you need to handle a specific exception, create a descendant of this class,
* pass handling exception class names into constructor, implement
* {@link #doHandle(Thread, String, String, Throwable)} method
* and register the new handler in the definition of {@link ExceptionHandlersConfiguration} bean in the client's
* spring.xml.
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public abstract class AbstractExceptionHandler<T extends Throwable> implements ExceptionHandler {
public abstract class AbstractExceptionHandler implements ExceptionHandler {
private final Class<T> tClass;
private List<String> classNames;
public AbstractExceptionHandler(Class<T> tClass) {
this.tClass = tClass;
protected AbstractExceptionHandler(String... classNames) {
this.classNames = Arrays.asList(classNames);
}
@Override
@SuppressWarnings("unchecked")
public boolean handle(Thread thread, Throwable exception) {
Throwable t = exception;
while (t != null) {
if (tClass.isAssignableFrom(t.getClass())) {
doHandle(thread, (T) t);
List<Throwable> list = ExceptionUtils.getThrowableList(exception);
for (Throwable throwable : list) {
if (classNames.contains(throwable.getClass().getName())) {
doHandle(thread, throwable.getClass().getName(), throwable.getMessage(), throwable);
return true;
}
t = t.getCause();
if (throwable instanceof RemoteException) {
RemoteException remoteException = (RemoteException) throwable;
for (RemoteException.Cause cause : remoteException.getCauses()) {
if (classNames.contains(cause.getClassName())) {
doHandle(thread, cause.getClassName(), cause.getMessage(), cause.getThrowable());
return true;
}
}
}
}
return false;
}
protected abstract void doHandle(Thread thread, T t);
protected abstract void doHandle(Thread thread, String className, String message, @Nullable Throwable throwable);
protected String getMessage(String key) {
return MessageProvider.getMessage(AppConfig.getMessagesPack(), key, App.getInstance().getLocale());

View File

@ -11,18 +11,23 @@ import com.haulmont.cuba.core.global.MessageProvider;
import com.haulmont.cuba.desktop.App;
import com.haulmont.cuba.gui.components.IFrame;
import javax.annotation.Nullable;
/**
* Handles {@link AccessDeniedException}.
*
* <p>$Id$</p>
*
* @author devyatkin
*/
public class AccessDeniedHandler extends AbstractExceptionHandler<AccessDeniedException> {
public class AccessDeniedHandler extends AbstractExceptionHandler {
public AccessDeniedHandler() {
super(AccessDeniedException.class);
super(AccessDeniedException.class.getName());
}
@Override
protected void doHandle(Thread thread, AccessDeniedException e) {
protected void doHandle(Thread thread, String className, String message, @Nullable Throwable throwable) {
String msg = MessageProvider.getMessage(getClass(), "accessDenied.message");
App.getInstance().showNotificationPopup(msg, IFrame.NotificationType.ERROR);
}

View File

@ -17,6 +17,9 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Handles {@link DeletePolicyException}. Determines the exception type by searching a special marker string in the
* messages of all exceptions in the chain.
*
* <p>$Id$</p>
*
* @author devyatkin
@ -28,8 +31,8 @@ public class DeletePolicyHandler implements ExceptionHandler {
Throwable t = exception;
try {
while (t != null) {
if (t.getMessage() != null && t.getMessage().contains(getMarker())) {
doHandle(thread, t.getMessage());
if (t.toString().contains(getMarker())) {
doHandle(thread, t.toString());
return true;
}
t = t.getCause();

View File

@ -11,18 +11,23 @@ import com.haulmont.cuba.core.global.MessageProvider;
import com.haulmont.cuba.desktop.App;
import com.haulmont.cuba.gui.components.IFrame;
import javax.annotation.Nullable;
/**
* Handles {@link EntityDeletedException}.
*
* <p>$Id$</p>
*
* @author pavlov
*/
public class EntityDeletedExceptionHandler extends AbstractExceptionHandler<EntityDeletedException>{
public class EntityDeletedExceptionHandler extends AbstractExceptionHandler {
public EntityDeletedExceptionHandler() {
super(EntityDeletedException.class);
super(EntityDeletedException.class.getName());
}
@Override
protected void doHandle(Thread thread, EntityDeletedException e) {
protected void doHandle(Thread thread, String className, String message, @Nullable Throwable throwable) {
String msg = MessageProvider.formatMessage(getClass(), "entityDeletedException.message");
App.getInstance().showNotificationPopup(msg, IFrame.NotificationType.WARNING);
}

View File

@ -6,25 +6,43 @@
package com.haulmont.cuba.desktop.exception;
import com.haulmont.bali.util.ReflectionHelper;
import com.haulmont.cuba.core.sys.AppContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.annotation.ManagedBean;
import java.util.LinkedList;
import java.util.Map;
/**
* Class that holds the collection of exception handlers and delegates unhandled exception processing to them. Handlers
* form the chain of responsibility.
*
* <p>A set of exception handlers is configured by defining <code>ExceptionHandlersConfiguration</code> beans
* in spring.xml. If a project needs specific handlers, it should define a bean of such type with its own
* <strong>id</strong>, e.g. <code>refapp_ExceptionHandlersConfiguration</code></p>
*
* <p>$Id$</p>
*
* @author krivopustov
*/
@ManagedBean("cuba_ExceptionHandlers")
public class ExceptionHandlers {
private LinkedList<ExceptionHandler> handlers = new LinkedList<ExceptionHandler>();
protected LinkedList<ExceptionHandler> handlers = new LinkedList<ExceptionHandler>();
private ExceptionHandler defaultHandler;
protected ExceptionHandler defaultHandler;
private Log log = LogFactory.getLog(getClass());
public ExceptionHandlers() {
this.defaultHandler = new DefaultExceptionHandler();
}
/**
* Adds new handler if it is not yet registered
* Adds new handler if it is not yet registered.
* @param handler handler instance
*/
public void addHandler(ExceptionHandler handler) {
if (!handlers.contains(handler))
@ -32,14 +50,17 @@ public class ExceptionHandlers {
}
/**
* All registered handlers
* Return all registered handlers.
* @return modifiable handlers list
*/
public LinkedList<ExceptionHandler> getHandlers() {
return handlers;
}
/**
* Delegates exception handling to registered handlers
* Delegates exception handling to registered handlers.
* @param thread current thread
* @param exception exception instance
*/
public void handle(Thread thread, Throwable exception) {
for (ExceptionHandler handler : handlers) {
@ -48,4 +69,27 @@ public class ExceptionHandlers {
}
defaultHandler.handle(thread, exception);
}
/**
* Create all handlers defined by <code>ExceptionHandlersConfiguration</code> beans in spring.xml.
*/
public void createByConfiguration() {
Map<String, ExceptionHandlersConfiguration> map = AppContext.getBeansOfType(ExceptionHandlersConfiguration.class);
for (ExceptionHandlersConfiguration conf : map.values()) {
for (Class aClass : conf.getHandlerClasses()) {
try {
handlers.add(ReflectionHelper.<ExceptionHandler>newInstance(aClass));
} catch (NoSuchMethodException e) {
log.error("Unable to instantiate " + aClass, e);
}
}
}
}
/**
* Remove all handlers.
*/
public void removeAll() {
handlers.clear();
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
*/
package com.haulmont.cuba.desktop.exception;
import com.haulmont.bali.util.ReflectionHelper;
import java.util.ArrayList;
import java.util.List;
/**
* Class that is used to configure {@link ExceptionHandlers} via spring.xml.
*
* <p>If a project needs specific exception handlers, it should define a bean of this type with its own
* <strong>id</strong>, e.g. <code>refapp_ExceptionHandlersConfiguration</code>, and set the list of handler class
* names in <code>handlerClasses</code> property.</p>
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class ExceptionHandlersConfiguration {
private List<Class> handlerClasses = new ArrayList<Class>();
/**
* Set the list of exception handler class names, usually from spring.xml.
* @param list list of class names
*/
public void setHandlerClasses(List<String> list) {
for (String className : list) {
handlerClasses.add(ReflectionHelper.getClass(className));
}
}
/**
* Get the list of exception handler class names.
* @return list of class names
*/
public List<Class> getHandlerClasses() {
return handlerClasses;
}
}

View File

@ -11,19 +11,25 @@ import com.haulmont.cuba.desktop.App;
import com.haulmont.cuba.gui.components.IFrame;
import com.haulmont.cuba.gui.export.FileMissingException;
import javax.annotation.Nullable;
/**
* Handles {@link FileMissingException}.
*
* <p>$Id$</p>
*
* @author artamonov
*/
public class FileMissingExceptionHandler extends AbstractExceptionHandler<FileMissingException> {
public class FileMissingExceptionHandler extends AbstractExceptionHandler {
public FileMissingExceptionHandler() {
super(FileMissingException.class);
super(FileMissingException.class.getName());
}
@Override
protected void doHandle(Thread thread, FileMissingException e) {
String msg = MessageProvider.formatMessage(getClass(), "fileNotFoundWarning.message", e.getFileName());
protected void doHandle(Thread thread, String className, String message, @Nullable Throwable throwable) {
String fileName = throwable != null ? ((FileMissingException) throwable).getFileName() : "?";
String msg = MessageProvider.formatMessage(getClass(), "fileNotFoundWarning.message", fileName);
App.getInstance().showNotificationPopup(msg, IFrame.NotificationType.ERROR);
}
}

View File

@ -1,45 +0,0 @@
/*
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
*/
package com.haulmont.cuba.desktop.exception;
import com.haulmont.cuba.core.global.MessageProvider;
import com.haulmont.cuba.desktop.App;
import com.haulmont.cuba.gui.components.IFrame;
import javax.persistence.OptimisticLockException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* <p>$Id$</p>
*
* @author artamonov
*/
public class JPAOptimisticExceptionHandler extends AbstractExceptionHandler<OptimisticLockException> {
public JPAOptimisticExceptionHandler() {
super(OptimisticLockException.class);
}
@Override
protected void doHandle(Thread thread, OptimisticLockException e) {
Pattern pattern = Pattern.compile("\\[([^-]*)-");
Matcher matcher = pattern.matcher(e.getMessage());
String entityClassName = "";
if (matcher.find()) {
entityClassName = matcher.group(1);
}
String localizedEntityName;
String entityName = entityClassName.substring(entityClassName.lastIndexOf(".") + 1);
String packageName = entityClassName.substring(0, entityClassName.lastIndexOf("."));
localizedEntityName = MessageProvider.getMessage(packageName, entityName);
String msg = MessageProvider.formatMessage(getClass(), "optimisticException.message", "\"" + localizedEntityName + "\"");
App.getInstance().showNotificationPopup(msg, IFrame.NotificationType.ERROR);
}
}

View File

@ -11,19 +11,23 @@ import com.haulmont.cuba.desktop.App;
import com.haulmont.cuba.gui.NoSuchScreenException;
import com.haulmont.cuba.gui.components.IFrame;
import javax.annotation.Nullable;
/**
* Handles {@link NoSuchScreenException}.
*
* <p>$Id$</p>
*
* @author devyatkin
*/
public class NoSuchScreenHandler extends AbstractExceptionHandler<NoSuchScreenException> {
public class NoSuchScreenHandler extends AbstractExceptionHandler {
public NoSuchScreenHandler() {
super(NoSuchScreenException.class);
super(NoSuchScreenException.class.getName());
}
@Override
protected void doHandle(Thread thread, NoSuchScreenException e) {
protected void doHandle(Thread thread, String className, String message, @Nullable Throwable throwable) {
String msg = MessageProvider.getMessage(getClass(), "noSuchScreen.message");
App.getInstance().showNotificationPopup(msg, IFrame.NotificationType.ERROR);
}

View File

@ -12,21 +12,25 @@ import com.haulmont.cuba.security.global.NoUserSessionException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.annotation.Nullable;
/**
* Handles {@link NoUserSessionException}.
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class NoUserSessionHandler extends AbstractExceptionHandler<NoUserSessionException> {
public class NoUserSessionHandler extends AbstractExceptionHandler {
private static Log log = LogFactory.getLog(NoUserSessionHandler.class);
public NoUserSessionHandler() {
super(NoUserSessionException.class);
super(NoUserSessionException.class.getName());
}
@Override
protected void doHandle(Thread thread, NoUserSessionException e) {
protected void doHandle(Thread thread, String className, String message, @Nullable Throwable throwable) {
try {
App.getInstance().getWindowManager().showOptionDialog(
getMessage("dialogs.Information"),

View File

@ -12,20 +12,24 @@ import com.haulmont.cuba.gui.components.IFrame;
import org.apache.commons.lang.StringUtils;
import org.apache.openjpa.lib.jdbc.ReportingSQLException;
import javax.annotation.Nullable;
/**
* Handles database "numeric overflow" exception.
*
* <p>$Id$</p>
*
* @author devyatkin
*/
public class NumericOverflowExceptionHandler extends AbstractExceptionHandler<ReportingSQLException> {
public class NumericOverflowExceptionHandler extends AbstractExceptionHandler {
public NumericOverflowExceptionHandler() {
super(ReportingSQLException.class);
super(ReportingSQLException.class.getName());
}
@Override
protected void doHandle(Thread thread, ReportingSQLException e) {
if (StringUtils.containsIgnoreCase(e.getMessage(), MessageProvider.getMessage(getClass(), "numericFieldOverflow.marker"))) {
protected void doHandle(Thread thread, String className, String message, @Nullable Throwable throwable) {
if (StringUtils.containsIgnoreCase(message, "Numeric field overflow")) {
String msg = MessageProvider.getMessage(getClass(), "numericFieldOverflow.message");
App.getInstance().showNotificationPopup(msg, IFrame.NotificationType.ERROR);
}

View File

@ -9,34 +9,37 @@ package com.haulmont.cuba.desktop.exception;
import com.haulmont.cuba.core.global.MessageProvider;
import com.haulmont.cuba.desktop.App;
import com.haulmont.cuba.gui.components.IFrame;
import org.apache.openjpa.util.OptimisticException;
import javax.annotation.Nullable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Handles a JPA optimistic lock exception.
*
* <p>$Id$</p>
*
* @author artamonov
*/
public class OptimisticExceptionHandler extends AbstractExceptionHandler<OptimisticException> {
public class OptimisticExceptionHandler extends AbstractExceptionHandler {
public OptimisticExceptionHandler() {
super(OptimisticException.class);
super("org.springframework.orm.jpa.JpaOptimisticLockingFailureException");
}
@Override
protected void doHandle(Thread thread, OptimisticException e) {
protected void doHandle(Thread thread, String className, String message, @Nullable Throwable throwable) {
Pattern pattern = Pattern.compile("\\[([^-]*)-");
Matcher matcher = pattern.matcher(e.getMessage());
String entityClassName = "";
if (matcher.find()) {
entityClassName = matcher.group(1);
}
Matcher matcher = pattern.matcher(message);
String localizedEntityName;
String entityName = entityClassName.substring(entityClassName.lastIndexOf(".") + 1);
String packageName = entityClassName.substring(0, entityClassName.lastIndexOf("."));
localizedEntityName = MessageProvider.getMessage(packageName, entityName);
if (matcher.find()) {
String entityClassName = matcher.group(1);
String entityName = entityClassName.substring(entityClassName.lastIndexOf(".") + 1);
String packageName = entityClassName.substring(0, entityClassName.lastIndexOf("."));
localizedEntityName = MessageProvider.getMessage(packageName, entityName);
} else {
localizedEntityName = "?";
}
String msg = MessageProvider.formatMessage(getClass(), "optimisticException.message", "\"" + localizedEntityName + "\"");
App.getInstance().showNotificationPopup(msg, IFrame.NotificationType.ERROR);

View File

@ -13,23 +13,31 @@ import com.haulmont.cuba.report.exception.FailedToConnectToOpenOfficeException;
import com.haulmont.cuba.report.exception.ReportingException;
import com.haulmont.cuba.report.exception.UnsupportedFormatException;
import javax.annotation.Nullable;
/**
* Handles reporting exceptions.
*
* <p>$Id$</p>
*
* @author devyatkin
*/
public class ReportExceptionHandler extends AbstractExceptionHandler<ReportingException> {
public class ReportExceptionHandler extends AbstractExceptionHandler {
public ReportExceptionHandler() {
super(ReportingException.class);
super(
ReportingException.class.getName(),
FailedToConnectToOpenOfficeException.class.getName(),
UnsupportedFormatException.class.getName()
);
}
@Override
protected void doHandle(Thread thread, ReportingException e) {
protected void doHandle(Thread thread, String className, String message, @Nullable Throwable throwable) {
String messageCode = "reportException.message";
if (e instanceof FailedToConnectToOpenOfficeException) {
if (FailedToConnectToOpenOfficeException.class.getName().equals(className)) {
messageCode = "reportException.failedConnectToOffice";
} else if (e instanceof UnsupportedFormatException) {
} else if (UnsupportedFormatException.class.getName().equals(className)) {
messageCode = "reportException.unsupportedFileFormat";
}
String msg = MessageProvider.getMessage(getClass(), messageCode);

View File

@ -8,18 +8,22 @@ package com.haulmont.cuba.desktop.exception;
import com.haulmont.cuba.core.global.SilentException;
import javax.annotation.Nullable;
/**
* Handler that does nothing in respond to {@link SilentException}.
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class SilentExceptionHandler extends AbstractExceptionHandler<SilentException> {
public class SilentExceptionHandler extends AbstractExceptionHandler {
public SilentExceptionHandler() {
super(SilentException.class);
super(SilentException.class.getName());
}
@Override
protected void doHandle(Thread thread, SilentException e) {
protected void doHandle(Thread thread, String className, String message, @Nullable Throwable throwable) {
}
}

View File

@ -12,12 +12,14 @@ import com.haulmont.cuba.desktop.App;
import com.haulmont.cuba.gui.ServiceLocator;
import com.haulmont.cuba.gui.components.IFrame;
import org.apache.commons.lang.StringUtils;
import org.springframework.orm.jpa.JpaSystemException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Handles database unique constraint violations. Determines the exception type by searching a special marker string
* in the messages of all exceptions in the chain.
*
* <p>$Id$</p>
*
* @author devyatkin
@ -48,7 +50,7 @@ public class UniqueConstraintViolationHandler implements ExceptionHandler {
Throwable t = exception;
try {
while (t != null) {
if (t.getMessage() != null && t.getMessage().contains(getMarker())) {
if (t.toString().contains(getMarker())) {
doHandle(thread, t);
return true;
}
@ -62,7 +64,7 @@ public class UniqueConstraintViolationHandler implements ExceptionHandler {
protected void doHandle(Thread thread, Throwable e) {
String constraintName = "";
Matcher matcher = getPattern().matcher(e.getMessage());
Matcher matcher = getPattern().matcher(e.toString());
if (matcher.find()) {
if (matcher.groupCount() > 1)
constraintName = matcher.group(2);

View File

@ -53,6 +53,26 @@
</property>
</bean>
<!-- Exception handlers -->
<bean id="cuba_exceptionHandlersConf" class="com.haulmont.cuba.desktop.exception.ExceptionHandlersConfiguration">
<property name="handlerClasses">
<list>
<value>com.haulmont.cuba.desktop.exception.NoUserSessionHandler</value>
<value>com.haulmont.cuba.desktop.exception.SilentExceptionHandler</value>
<value>com.haulmont.cuba.desktop.exception.UniqueConstraintViolationHandler</value>
<value>com.haulmont.cuba.desktop.exception.AccessDeniedHandler</value>
<value>com.haulmont.cuba.desktop.exception.NoSuchScreenHandler</value>
<value>com.haulmont.cuba.desktop.exception.DeletePolicyHandler</value>
<value>com.haulmont.cuba.desktop.exception.NumericOverflowExceptionHandler</value>
<value>com.haulmont.cuba.desktop.exception.OptimisticExceptionHandler</value>
<value>com.haulmont.cuba.desktop.exception.ReportExceptionHandler</value>
<value>com.haulmont.cuba.desktop.exception.FileMissingExceptionHandler</value>
<value>com.haulmont.cuba.desktop.exception.EntityDeletedExceptionHandler</value>
</list>
</property>
</bean>
<!-- Background Tasks -->
<bean id="cuba_BackgroundWorker_WatchDog" class="com.haulmont.cuba.gui.executors.TasksWatchDog"/>

View File

@ -1,24 +1,28 @@
/*
* Copyright (c) 2008 Haulmont Technology Ltd. All Rights Reserved.
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
* Author: Konstantin Krivopustov
* Created: 25.12.2008 13:24:09
*
* $Id$
*/
package com.haulmont.cuba.core.global;
import com.haulmont.cuba.core.sys.ClassesInfo;
import com.haulmont.cuba.security.entity.PermissionType;
/**
* This exception is raised on attempt to violate a security constraint
* Exception that is raised on attempt to violate a security constraint.
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class AccessDeniedException extends RuntimeException
{
private static final long serialVersionUID = -3097861878301424338L;
static {
ClassesInfo.addClientSupported(AccessDeniedException.class);
}
private PermissionType type;
private String target;

View File

@ -11,9 +11,13 @@
package com.haulmont.cuba.core.global;
/**
* This exception is raised on attempt to soft delete an object,
* which has linked objects marked with {@link OnDelete} annotation
* with {@link com.haulmont.cuba.core.global.DeletePolicy} DENY value
* Exception that is raised on attempt to soft delete an object,
* which has linked objects marked with {@link com.haulmont.cuba.core.entity.annotation.OnDelete} annotation
* with {@link com.haulmont.cuba.core.global.DeletePolicy#DENY} value.
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class DeletePolicyException extends RuntimeException
{

View File

@ -7,14 +7,12 @@
package com.haulmont.cuba.core.global;
/**
* This exception is raised on attempt to load a deleted object.
*
* <p>$Id$</p>
*
* @author pavlov
*/
/**
* This exception is raised on attempt to load deleted object
*/
public class EntityDeletedException extends RuntimeException {
public static final String ERR_MESSAGE = "Unable to load entiny because it has been deleted";

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
*/
package com.haulmont.cuba.core.global;
import com.haulmont.cuba.core.sys.ClassesInfo;
import org.apache.commons.lang.exception.ExceptionUtils;
import javax.annotation.Nullable;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Exception that returns to clients from the middleware. Contains the information about the whole server-side
* exception chain in the <code>Cause</code> objects list. Actual exception instances are included only if they
* explicitly made available for the clients (registered in {@link ClassesInfo}).
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class RemoteException extends RuntimeException {
public static class Cause implements Serializable {
private String className;
private String message;
private Throwable throwable;
public Cause(Throwable throwable) {
className = throwable.getClass().getName();
message = throwable.getMessage();
if (ClassesInfo.isClientSupported(throwable.getClass()))
this.throwable = throwable;
}
public String getClassName() {
return className;
}
public String getMessage() {
return message;
}
@Nullable
public Throwable getThrowable() {
return throwable;
}
@Override
public String toString() {
return className + ": " + message;
}
}
private List<Cause> causes = new ArrayList<Cause>();
@SuppressWarnings("unchecked")
public RemoteException(Throwable throwable) {
List<Throwable> list = ExceptionUtils.getThrowableList(throwable);
for (Throwable t : list) {
causes.add(new Cause(t));
}
}
public List<Cause> getCauses() {
return Collections.unmodifiableList(causes);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("RemoteException:");
for (Cause cause : causes) {
sb.append("\n---\n").append(cause.getClassName()).append(": ").append(cause.getMessage());
}
return sb.toString();
}
}

View File

@ -1,15 +1,17 @@
/*
* Copyright (c) 2009 Haulmont Technology Ltd. All Rights Reserved.
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
* Author: Konstantin Krivopustov
* Created: 15.01.2010 16:40:25
*
* $Id$
*/
package com.haulmont.cuba.core.global;
/**
* Exception that is used to interrupt an execution flow without any messages to the user.
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class SilentException extends RuntimeException {
private static final long serialVersionUID = 6598108074890603763L;

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
*/
package com.haulmont.cuba.core.sys;
import java.util.ArrayList;
import java.util.List;
/**
* Class that provides information about classes availability for different application layers.
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class ClassesInfo {
private static List<Class> clientSupported = new ArrayList<Class>();
/**
* Register a class as available for the client layer.
* @param aClass class
*/
public static synchronized void addClientSupported(Class aClass) {
if (!clientSupported.contains(aClass))
clientSupported.add(aClass);
}
/**
* Check whether the class is available for the client layer.
* @param aClass class
* @return true if available
*/
public static synchronized boolean isClientSupported(Class aClass) {
return clientSupported.contains(aClass);
}
}

View File

@ -1,26 +1,29 @@
/*
* Copyright (c) 2008 Haulmont Technology Ltd. All Rights Reserved.
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
* Author: Konstantin Krivopustov
* Created: 02.12.2008 13:14:32
*
* $Id$
*/
package com.haulmont.cuba.security.global;
import com.haulmont.cuba.core.global.MessageProvider;
import com.haulmont.cuba.core.sys.ClassesInfo;
import java.util.UUID;
/**
* Raised by middleware if client provides an invalid user session ID (e.g. if the user session is expired)
* Raised by middleware if the client provides an invalid user session ID (e.g. if the user session has expired).
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class NoUserSessionException extends RuntimeException
{
private static final long serialVersionUID = 4820628023682230319L;
static {
ClassesInfo.addClientSupported(NoUserSessionException.class);
}
public NoUserSessionException(UUID sessionId) {
super(String.format("User session not found: %s", sessionId.toString()));
}

View File

@ -1,15 +1,17 @@
/*
* Copyright (c) 2008 Haulmont Technology Ltd. All Rights Reserved.
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
* Author: Konstantin Krivopustov
* Created: 28.07.2009 10:05:20
*
* $Id$
*/
package com.haulmont.cuba.gui;
/**
* Raised on attempt to open an unknown screen.
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class NoSuchScreenException extends RuntimeException {
private static final long serialVersionUID = -3751833162235475862L;

View File

@ -155,8 +155,6 @@ entityLocked.desc=Record is locked by %s since %s
tooManyOpenTabs.message=Too many open tabs (Max %d).<br>Please close not used.
numericFieldOverflow.marker=Numeric field overflow
validationFail.caption=Alert
validationFail=Input error
invalidValue=Invalid value for "%s"

View File

@ -20,7 +20,7 @@ import com.haulmont.cuba.gui.AppConfig;
import com.haulmont.cuba.gui.ServiceLocator;
import com.haulmont.cuba.security.app.UserSessionService;
import com.haulmont.cuba.security.global.UserSession;
import com.haulmont.cuba.web.exception.*;
import com.haulmont.cuba.web.exception.ExceptionHandlers;
import com.haulmont.cuba.web.gui.WebTimer;
import com.haulmont.cuba.web.log.AppLog;
import com.haulmont.cuba.web.sys.ActiveDirectoryHelper;
@ -243,25 +243,15 @@ public abstract class App extends Application
}
/**
* Can be overridden in descendant to add application-specific exception handlers
* Initializes exception handlers immediately after login and logout.
* Can be overridden in descendants to manipulate exception handlers programmatically.
* @param isConnected true after login, false after logout
*/
protected void initExceptionHandlers(boolean isConnected) {
if (isConnected) {
exceptionHandlers.addHandler(new NoUserSessionHandler()); // must be the first handler
exceptionHandlers.addHandler(new SilentExceptionHandler());
exceptionHandlers.addHandler(new UniqueConstraintViolationHandler());
exceptionHandlers.addHandler(new AccessDeniedHandler());
exceptionHandlers.addHandler(new NoSuchScreenHandler());
exceptionHandlers.addHandler(new DeletePolicyHandler());
exceptionHandlers.addHandler(new NumericOverflowExceptionHandler());
exceptionHandlers.addHandler(new OptimisticExceptionHandler());
exceptionHandlers.addHandler(new JPAOptimisticExceptionHandler());
exceptionHandlers.addHandler(new ReportExceptionHandler());
exceptionHandlers.addHandler(new FileMissingExceptionHandler());
exceptionHandlers.addHandler(new InvalidValueExceptionHandler());
exceptionHandlers.addHandler(new EntityDeletedExceptionHandler());
exceptionHandlers.createByConfiguration();
} else {
exceptionHandlers.getHandlers().clear();
exceptionHandlers.removeAll();
}
}

View File

@ -10,35 +10,65 @@
*/
package com.haulmont.cuba.web.exception;
import com.vaadin.terminal.Terminal;
import com.haulmont.cuba.core.global.RemoteException;
import com.haulmont.cuba.web.App;
import com.vaadin.terminal.Terminal;
import org.apache.commons.lang.exception.ExceptionUtils;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.List;
/**
* Base class for exception handler bound to specific exception type.
* <p>
* If you need to handle a specific exception, create a descendant of this class,
* pass handling exception class into constructor, implement {@link #doHandle(Throwable,com.haulmont.cuba.web.App)} method
* and register the new handler in {@link App#initExceptionHandlers(boolean)}.
* Base class for exception handlers determining their ability to handle an exception by its class name.
*
* <p>If you need to handle a specific exception, create a descendant of this class,
* pass handling exception class names into constructor, implement
* {@link #doHandle(com.haulmont.cuba.web.App, String, String, Throwable)} method
* and register the new handler in the definition of {@link ExceptionHandlersConfiguration} bean in the client's
* spring.xml.
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public abstract class AbstractExceptionHandler<T extends Throwable> implements ExceptionHandler {
public abstract class AbstractExceptionHandler implements ExceptionHandler {
private final Class<T> tClass;
private List<String> classNames;
public AbstractExceptionHandler(Class<T> tClass) {
this.tClass = tClass;
protected AbstractExceptionHandler(String... classNames) {
this.classNames = Arrays.asList(classNames);
}
@Override
public boolean handle(Terminal.ErrorEvent event, App app) {
Throwable t = event.getThrowable();
while (t != null) {
if (tClass.isAssignableFrom(t.getClass())) {
doHandle((T) t, app);
Throwable exception = event.getThrowable();
List<Throwable> list = ExceptionUtils.getThrowableList(exception);
for (Throwable throwable : list) {
if (classNames.contains(throwable.getClass().getName())) {
doHandle(app, throwable.getClass().getName(), throwable.getMessage(), throwable);
return true;
}
t = t.getCause();
if (throwable instanceof RemoteException) {
RemoteException remoteException = (RemoteException) throwable;
for (RemoteException.Cause cause : remoteException.getCauses()) {
if (classNames.contains(cause.getClassName())) {
doHandle(app, cause.getClassName(), cause.getMessage(), cause.getThrowable());
return true;
}
}
}
}
return false;
}
protected abstract void doHandle(T t, App app);
/**
* Perform exception handling.
* @param app current {@link App} instance
* @param className actual exception class name
* @param message exception message
* @param throwable exception instance. Can be null if the exception occured on the server side and this
* exception class isn't accessible by the client.
*/
protected abstract void doHandle(App app, String className, String message, @Nullable Throwable throwable);
}

View File

@ -15,18 +15,28 @@ import com.haulmont.cuba.core.global.MessageProvider;
import com.haulmont.cuba.web.App;
import com.vaadin.ui.Window;
public class AccessDeniedHandler extends AbstractExceptionHandler<AccessDeniedException> {
import javax.annotation.Nullable;
/**
* Handles {@link AccessDeniedException}.
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class AccessDeniedHandler extends AbstractExceptionHandler {
public AccessDeniedHandler() {
super(AccessDeniedException.class);
super(AccessDeniedException.class.getName());
}
protected void doHandle(AccessDeniedException t, App app) {
@Override
protected void doHandle(App app, String className, String message, @Nullable Throwable throwable) {
String msg = MessageProvider.getMessage(getClass(), "accessDenied.message");
app.getAppWindow().showNotification(msg, Window.Notification.TYPE_ERROR_MESSAGE);
}
public void handle(AccessDeniedException e, App app) {
doHandle(e, app);
doHandle(app, AccessDeniedException.class.getName(), e.getMessage(), e);
}
}

View File

@ -1,12 +1,7 @@
/*
* Copyright (c) 2008 Haulmont Technology Ltd. All Rights Reserved.
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
* Author: Konstantin Krivopustov
* Created: 20.05.2009 18:32:01
*
* $Id$
*/
package com.haulmont.cuba.web.exception;
@ -18,19 +13,21 @@ import com.haulmont.cuba.web.App;
import java.net.SocketException;
/**
* This exception handler comes into play if no other handler has handled the exception
* This exception handler comes into play if no other handler in the chain has handled the exception.
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class DefaultExceptionHandler implements ExceptionHandler
{
@Override
public boolean handle(Terminal.ErrorEvent event, App app) {
// Copied from com.vaadin.Application.terminalError()
Throwable t = event.getThrowable();
if (t instanceof SocketException) {
// Most likely client browser closed socket
// System.err
// .println("Warning: SocketException in CommunicationManager."
// + " Most likely client (browser) closed socket.");
return true;
}
@ -55,12 +52,6 @@ public class DefaultExceptionHandler implements ExceptionHandler
((AbstractComponent) owner)
.setComponentError(new SystemError(e));
}
} else {
/*
* Can't show it to the user in any way so we print to standard
* error
*/
// t.printStackTrace();
}
return true;
}

View File

@ -1,12 +1,7 @@
/*
* Copyright (c) 2008 Haulmont Technology Ltd. All Rights Reserved.
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
* Author: Ilya Grachev
* Created: 29.07.2009 18:51:21
*
* $Id$
*/
package com.haulmont.cuba.web.exception;
@ -19,6 +14,14 @@ import com.vaadin.ui.Window;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Handles {@link DeletePolicyException}. Determines the exception type by searching a special marker string in the
* messages of all exceptions in the chain.
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class DeletePolicyHandler implements ExceptionHandler {
@Override
@ -26,8 +29,8 @@ public class DeletePolicyHandler implements ExceptionHandler {
Throwable t = event.getThrowable();
try {
while (t != null) {
if (t.getMessage() != null && t.getMessage().contains(getMarker())) {
doHandle(t.getMessage(), app);
if (t.toString().contains(getMarker())) {
doHandle(t.toString(), app);
return true;
}
t = t.getCause();

View File

@ -11,19 +11,23 @@ import com.haulmont.cuba.core.global.MessageProvider;
import com.haulmont.cuba.web.App;
import com.vaadin.ui.Window;
import javax.annotation.Nullable;
/**
* Handles {@link EntityDeletedException}.
*
* <p>$Id$</p>
*
* @author pavlov
*/
public class EntityDeletedExceptionHandler extends AbstractExceptionHandler<EntityDeletedException> {
public class EntityDeletedExceptionHandler extends AbstractExceptionHandler {
public EntityDeletedExceptionHandler() {
super(EntityDeletedException.class);
super(EntityDeletedException.class.getName());
}
@Override
protected void doHandle(EntityDeletedException e, App app) {
protected void doHandle(App app, String className, String message, @Nullable Throwable throwable) {
String msg = MessageProvider.formatMessage(getClass(), "entityDeletedException.message");
app.getAppWindow().showNotification(msg, Window.Notification.TYPE_WARNING_MESSAGE);
}

View File

@ -18,7 +18,11 @@ import com.vaadin.ui.Window;
import com.vaadin.ui.Button;
/**
* This dialog can be used by exception handlers to show an information about error
* This dialog can be used by exception handlers to show an information about error.
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class ExceptionDialog extends Window
{

View File

@ -16,9 +16,20 @@ import com.haulmont.cuba.web.App;
import java.io.Serializable;
/**
* Interface implemented by unhandled exception handler in WebUI
* Interface to be implemented by exception handlers in Web-client.
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public interface ExceptionHandler extends Serializable
{
/**
* Handle an exception. Implementation class should either handle the exception and return true, or return false
* to delegate execution to the next handler in the chain of responsibility.
* @param event error event containing the exception, generated by Vaadin
* @param app current {@link App} instance
* @return true if the exception has been succesfully handled, false if not
*/
boolean handle(Terminal.ErrorEvent event, App app);
}

View File

@ -10,33 +10,51 @@
*/
package com.haulmont.cuba.web.exception;
import com.haulmont.bali.util.ReflectionHelper;
import com.haulmont.cuba.core.sys.AppContext;
import com.haulmont.cuba.web.App;
import com.vaadin.terminal.Terminal;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.Map;
/**
* Provides extensible exception handling functionality.
* See also {@link App#initExceptionHandlers(boolean)}
* Class that holds the collection of exception handlers and delegates unhandled exception processing to them. Handlers
* form the chain of responsibility.
*
* <p>A set of exception handlers is configured by defining <code>ExceptionHandlersConfiguration</code> beans
* in spring.xml. If a project needs specific handlers, it should define a bean of such type with its own
* <strong>id</strong>, e.g. <code>refapp_ExceptionHandlersConfiguration</code></p>
*
* <p>An instance of this class is bound to {@link App}.</p>
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class ExceptionHandlers implements Serializable
{
private LinkedList<ExceptionHandler> handlers = new LinkedList<ExceptionHandler>();
private App app;
private ExceptionHandler defaultHandler;
private static final long serialVersionUID = 1458946417299293127L;
protected App app;
protected LinkedList<ExceptionHandler> handlers = new LinkedList<ExceptionHandler>();
protected ExceptionHandler defaultHandler;
private Log log = LogFactory.getLog(getClass());
public ExceptionHandlers(App app) {
this.app = app;
this.defaultHandler = new DefaultExceptionHandler();
}
/**
* Adds new handler if it is not yet registered
* Adds new handler if it is not yet registered.
* @param handler handler instance
*/
public void addHandler(ExceptionHandler handler) {
if (!handlers.contains(handler))
@ -44,14 +62,16 @@ public class ExceptionHandlers implements Serializable
}
/**
* All registered handlers
* Return all registered handlers.
* @return modifiable handlers list
*/
public LinkedList<ExceptionHandler> getHandlers() {
return handlers;
}
/**
* Delegates exception handling to registered handlers
* Delegates exception handling to registered handlers.
* @param event error event generated by Vaadin
*/
public void handle(Terminal.ErrorEvent event) {
for (ExceptionHandler handler : handlers) {
@ -60,4 +80,27 @@ public class ExceptionHandlers implements Serializable
}
defaultHandler.handle(event, app);
}
/**
* Create all handlers defined by <code>ExceptionHandlersConfiguration</code> beans in spring.xml.
*/
public void createByConfiguration() {
Map<String, ExceptionHandlersConfiguration> map = AppContext.getBeansOfType(ExceptionHandlersConfiguration.class);
for (ExceptionHandlersConfiguration conf : map.values()) {
for (Class aClass : conf.getHandlerClasses()) {
try {
addHandler(ReflectionHelper.<ExceptionHandler>newInstance(aClass));
} catch (NoSuchMethodException e) {
log.error("Unable to instantiate " + aClass, e);
}
}
}
}
/**
* Remove all handlers.
*/
public void removeAll() {
handlers.clear();
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
*/
package com.haulmont.cuba.web.exception;
import com.haulmont.bali.util.ReflectionHelper;
import java.util.ArrayList;
import java.util.List;
/**
* Class that is used to configure {@link ExceptionHandlers} via spring.xml.
*
* <p>If a project needs specific exception handlers, it should define a bean of this type with its own
* <strong>id</strong>, e.g. <code>refapp_ExceptionHandlersConfiguration</code>, and set the list of handler class
* names in <code>handlerClasses</code> property.</p>
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class ExceptionHandlersConfiguration {
private List<Class> handlerClasses = new ArrayList<Class>();
/**
* Set the list of exception handler class names, usually from spring.xml.
* @param list list of class names
*/
public void setHandlerClasses(List<String> list) {
for (String className : list) {
handlerClasses.add(ReflectionHelper.getClass(className));
}
}
/**
* Get the list of exception handler class names.
* @return list of class names
*/
public List<Class> getHandlerClasses() {
return handlerClasses;
}
}

View File

@ -11,25 +11,30 @@ import com.haulmont.cuba.gui.export.FileMissingException;
import com.haulmont.cuba.web.App;
import com.vaadin.ui.Window;
import javax.annotation.Nullable;
/**
* Handles {@link FileMissingException}.
*
* <p>$Id$</p>
*
* @author artamonov
*/
public class FileMissingExceptionHandler extends AbstractExceptionHandler<FileMissingException> {
public class FileMissingExceptionHandler extends AbstractExceptionHandler {
public FileMissingExceptionHandler() {
super(FileMissingException.class);
super(FileMissingException.class.getName());
}
@Override
protected void doHandle(FileMissingException t, App app) {
String msg = MessageProvider.formatMessage(getClass(), "fileNotFoundWarning.message", t.getFileName());
protected void doHandle(App app, String className, String message, @Nullable Throwable throwable) {
String fileName = throwable != null ? ((FileMissingException) throwable).getFileName() : "?";
String msg = MessageProvider.formatMessage(getClass(), "fileNotFoundWarning.message", fileName);
app.getAppWindow().showNotification(msg, Window.Notification.TYPE_WARNING_MESSAGE);
}
public boolean handle(FileMissingException e, App app) {
doHandle(e, app);
doHandle(app, FileMissingException.class.getName(), e.getMessage(), e);
return true;
}
}

View File

@ -11,19 +11,21 @@ import com.haulmont.cuba.web.App;
import com.vaadin.data.Validator;
import com.vaadin.ui.Window;
import javax.annotation.Nullable;
/**
* <p>$Id$</p>
*
* @author knst
* @author krivopustov
*/
public class InvalidValueExceptionHandler extends AbstractExceptionHandler<Validator.InvalidValueException> {
public class InvalidValueExceptionHandler extends AbstractExceptionHandler {
public InvalidValueExceptionHandler() {
super(Validator.InvalidValueException.class);
super(Validator.InvalidValueException.class.getName());
}
@Override
protected void doHandle(Validator.InvalidValueException e, App app) {
protected void doHandle(App app, String className, String message, @Nullable Throwable throwable) {
app.getAppWindow().showNotification(
MessageProvider.getMessage(getClass(), "validationFail.caption"),
MessageProvider.getMessage(getClass(), "validationFail"),

View File

@ -1,44 +0,0 @@
/*
* Copyright (c) 2008 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
* Author: Maksim Tulupov
* Created: 21.01.2010 10:07:21
*
* $Id$
*/
package com.haulmont.cuba.web.exception;
import com.haulmont.cuba.core.global.MessageProvider;
import com.haulmont.cuba.web.App;
import com.vaadin.ui.Window;
import org.apache.commons.lang.exception.ExceptionUtils;
import javax.persistence.OptimisticLockException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class JPAOptimisticExceptionHandler extends AbstractExceptionHandler<OptimisticLockException> {
public JPAOptimisticExceptionHandler() {
super(OptimisticLockException.class);
}
protected void doHandle(OptimisticLockException e, App app) {
Pattern pattern = Pattern.compile("\\[([^-]*)-");
Matcher matcher = pattern.matcher(ExceptionUtils.getStackTrace(e));
String entityClassName = "";
if (matcher.find()) {
entityClassName = matcher.group(1);
}
String localizedEntityName = "";
String entityName = entityClassName.substring(entityClassName.lastIndexOf(".") + 1);
String packageName = entityClassName.substring(0, entityClassName.lastIndexOf("."));
localizedEntityName = MessageProvider.getMessage(packageName, entityName);
String msg = MessageProvider.formatMessage(getClass(), "optimisticException.message", "\"" + localizedEntityName + "\"");
app.getAppWindow().showNotification(msg, Window.Notification.TYPE_ERROR_MESSAGE);
}
}

View File

@ -10,23 +10,32 @@
*/
package com.haulmont.cuba.web.exception;
import com.haulmont.cuba.core.global.MessageProvider;
import com.haulmont.cuba.gui.NoSuchScreenException;
import com.haulmont.cuba.web.App;
import com.haulmont.cuba.core.global.MessageProvider;
import com.vaadin.ui.Window;
public class NoSuchScreenHandler extends AbstractExceptionHandler<NoSuchScreenException> {
import javax.annotation.Nullable;
/**
* Handles {@link NoSuchScreenException}.
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class NoSuchScreenHandler extends AbstractExceptionHandler {
public NoSuchScreenHandler() {
super(NoSuchScreenException.class);
super(NoSuchScreenException.class.getName());
}
protected void doHandle(NoSuchScreenException t, App app) {
protected void doHandle(App app, String className, String message, @Nullable Throwable throwable) {
String msg = MessageProvider.getMessage(getClass(), "noSuchScreen.message");
app.getAppWindow().showNotification(msg, Window.Notification.TYPE_ERROR_MESSAGE);
}
public void handle(NoSuchScreenException e, App app) {
doHandle(e, app);
doHandle(app, NoSuchScreenException.class.getName(), e.getMessage(), e);
}
}

View File

@ -1,36 +1,42 @@
/*
* Copyright (c) 2009 Haulmont Technology Ltd. All Rights Reserved.
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
* Author: Konstantin Krivopustov
* Created: 25.09.2009 15:07:23
*
* $Id$
*/
package com.haulmont.cuba.web.exception;
import com.haulmont.cuba.gui.components.*;
import com.haulmont.cuba.web.App;
import com.haulmont.cuba.security.global.NoUserSessionException;
import com.haulmont.cuba.core.global.MessageProvider;
import com.haulmont.cuba.gui.components.Action;
import com.haulmont.cuba.gui.components.Component;
import com.haulmont.cuba.gui.components.DialogAction;
import com.haulmont.cuba.gui.components.IFrame;
import com.haulmont.cuba.security.global.NoUserSessionException;
import com.haulmont.cuba.web.App;
import com.vaadin.terminal.ExternalResource;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.annotation.Nullable;
import java.util.Locale;
public class NoUserSessionHandler extends AbstractExceptionHandler<NoUserSessionException> {
/**
* Handles {@link NoUserSessionException}.
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class NoUserSessionHandler extends AbstractExceptionHandler {
private static Log log = LogFactory.getLog(NoUserSessionHandler.class);
private Locale locale;
public NoUserSessionHandler() {
super(NoUserSessionException.class);
super(NoUserSessionException.class.getName());
locale = App.getInstance().getConnection().getSession().getLocale();
}
protected void doHandle(NoUserSessionException t, App app) {
protected void doHandle(App app, String className, String message, @Nullable Throwable throwable) {
try {
App.getInstance().getWindowManager().showOptionDialog(
MessageProvider.getMessage(getClass(), "dialogs.Information", locale),

View File

@ -1,12 +1,7 @@
/*
* Copyright (c) 2008 Haulmont Technology Ltd. All Rights Reserved.
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
* Author: Degtyarjov Eugeniy
* Created: 17.11.2009 14:57:21
*
* $Id$
*/
package com.haulmont.cuba.web.exception;
@ -17,13 +12,23 @@ import com.vaadin.ui.Window;
import org.apache.commons.lang.StringUtils;
import org.apache.openjpa.lib.jdbc.ReportingSQLException;
public class NumericOverflowExceptionHandler extends AbstractExceptionHandler<ReportingSQLException> {
import javax.annotation.Nullable;
/**
* Handles database "numeric overflow" exception.
*
* <p>$Id$</p>
*
* @author degtyarjov
*/
public class NumericOverflowExceptionHandler extends AbstractExceptionHandler {
public NumericOverflowExceptionHandler() {
super(ReportingSQLException.class);
super(ReportingSQLException.class.getName());
}
protected void doHandle(ReportingSQLException e, App app) {
if (StringUtils.containsIgnoreCase(e.getMessage(), MessageProvider.getMessage(getClass(), "numericFieldOverflow.marker"))) {
protected void doHandle(App app, String className, String message, @Nullable Throwable throwable) {
if (StringUtils.containsIgnoreCase(message, "Numeric field overflow")) {
String msg = MessageProvider.getMessage(getClass(), "numericFieldOverflow.message");
app.getAppWindow().showNotification(msg, Window.Notification.TYPE_ERROR_MESSAGE);
}

View File

@ -1,32 +1,35 @@
/*
* Copyright (c) 2009 Haulmont Technology Ltd. All Rights Reserved.
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
* Author: FIRSTNAME LASTNAME
* Created: 25.12.2009 10:22:36
*
* $Id$
*/
package com.haulmont.cuba.web.exception;
import com.haulmont.cuba.core.global.MessageProvider;
import com.haulmont.cuba.web.App;
import com.vaadin.ui.Window;
import org.apache.openjpa.util.OptimisticException;
import javax.annotation.Nullable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class OptimisticExceptionHandler extends AbstractExceptionHandler<OptimisticException>{
/**
* Handles a JPA optimistic lock exception.
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class OptimisticExceptionHandler extends AbstractExceptionHandler {
public OptimisticExceptionHandler() {
super(OptimisticException.class);
super("org.springframework.orm.jpa.JpaOptimisticLockingFailureException");
}
@Override
protected void doHandle(OptimisticException e, App app) {
protected void doHandle(App app, String className, String message, @Nullable Throwable throwable) {
Pattern pattern = Pattern.compile("\\[([^-]*)-");
Matcher matcher = pattern.matcher(e.getMessage());
Matcher matcher = pattern.matcher(message);
String entityClassName = "";
if (matcher.find()) {
entityClassName = matcher.group(1);

View File

@ -1,12 +1,7 @@
/*
* Copyright (c) 2010 Haulmont Technology Ltd. All Rights Reserved.
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
* Author: Yuryi Artamonov
* Created: 06.10.2010 14:57:32
*
* $Id$
*/
package com.haulmont.cuba.web.exception;
@ -17,17 +12,30 @@ import com.haulmont.cuba.report.exception.UnsupportedFormatException;
import com.haulmont.cuba.web.App;
import com.vaadin.ui.Window;
public class ReportExceptionHandler extends AbstractExceptionHandler<ReportingException> {
import javax.annotation.Nullable;
/**
* Handles reporting exceptions.
*
* <p>$Id$</p>
*
* @author artamonov
*/
public class ReportExceptionHandler extends AbstractExceptionHandler {
public ReportExceptionHandler() {
super(ReportingException.class);
super(
ReportingException.class.getName(),
FailedToConnectToOpenOfficeException.class.getName(),
UnsupportedFormatException.class.getName()
);
}
protected void doHandle(ReportingException t, App app) {
protected void doHandle(App app, String className, String message, @Nullable Throwable throwable) {
String messageCode = "reportException.message";
if (t instanceof FailedToConnectToOpenOfficeException) {
if (FailedToConnectToOpenOfficeException.class.getName().equals(className)) {
messageCode = "reportException.failedConnectToOffice";
} else if (t instanceof UnsupportedFormatException) {
} else if (UnsupportedFormatException.class.getName().equals(className)) {
messageCode = "reportException.unsupportedFileFormat";
}
String msg = MessageProvider.getMessage(getClass(), messageCode);
@ -35,7 +43,7 @@ public class ReportExceptionHandler extends AbstractExceptionHandler<ReportingEx
}
public boolean handle(ReportingException e, App app) {
doHandle(e, app);
doHandle(app, e.getClass().getName(), e.getMessage(), e);
return true;
}
}

View File

@ -1,25 +1,29 @@
/*
* Copyright (c) 2009 Haulmont Technology Ltd. All Rights Reserved.
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
* Author: Konstantin Krivopustov
* Created: 15.01.2010 16:42:17
*
* $Id$
*/
package com.haulmont.cuba.web.exception;
import com.haulmont.cuba.core.global.SilentException;
import com.haulmont.cuba.web.App;
public class SilentExceptionHandler extends AbstractExceptionHandler<SilentException> {
import javax.annotation.Nullable;
/**
* Handler that does nothing in respond to {@link SilentException}.
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class SilentExceptionHandler extends AbstractExceptionHandler {
public SilentExceptionHandler() {
super(SilentException.class);
super(SilentException.class.getName());
}
@Override
protected void doHandle(SilentException e, App app) {
protected void doHandle(App app, String className, String message, @Nullable Throwable throwable) {
}
}

View File

@ -1,17 +1,11 @@
/*
* Copyright (c) 2008 Haulmont Technology Ltd. All Rights Reserved.
* Copyright (c) 2011 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
* Author: Konstantin Krivopustov
* Created: 21.05.2009 10:41:48
*
* $Id$
*/
package com.haulmont.cuba.web.exception;
import com.haulmont.cuba.core.global.MessageUtils;
import com.haulmont.cuba.gui.components.IFrame;
import com.vaadin.terminal.Terminal;
import com.haulmont.cuba.web.App;
import com.haulmont.cuba.gui.ServiceLocator;
@ -22,6 +16,14 @@ import org.apache.commons.lang.StringUtils;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
/**
* Handles database unique constraint violations. Determines the exception type by searching a special marker string
* in the messages of all exceptions in the chain.
*
* <p>$Id$</p>
*
* @author krivopustov
*/
public class UniqueConstraintViolationHandler implements ExceptionHandler
{
private String marker;
@ -43,11 +45,12 @@ public class UniqueConstraintViolationHandler implements ExceptionHandler
return pattern;
}
@Override
public boolean handle(Terminal.ErrorEvent event, App app) {
Throwable t = event.getThrowable();
try {
while (t != null) {
if (t.getMessage() != null && t.getMessage().contains(getMarker())) {
if (t.toString().contains(getMarker())) {
doHandle(t, app);
return true;
}
@ -61,7 +64,7 @@ public class UniqueConstraintViolationHandler implements ExceptionHandler
private void doHandle(Throwable throwable, App app) {
String constraintName = "";
Matcher matcher = getPattern().matcher(throwable.getMessage());
Matcher matcher = getPattern().matcher(throwable.toString());
if (matcher.find()) {
if (matcher.groupCount() > 1)
constraintName = matcher.group(2);

View File

@ -76,7 +76,28 @@
</property>
</bean>
<!-- Scheduling setup -->
<!-- Exception handlers -->
<bean id="cuba_exceptionHandlersConf" class="com.haulmont.cuba.web.exception.ExceptionHandlersConfiguration">
<property name="handlerClasses">
<list>
<value>com.haulmont.cuba.web.exception.NoUserSessionHandler</value>
<value>com.haulmont.cuba.web.exception.SilentExceptionHandler</value>
<value>com.haulmont.cuba.web.exception.UniqueConstraintViolationHandler</value>
<value>com.haulmont.cuba.web.exception.AccessDeniedHandler</value>
<value>com.haulmont.cuba.web.exception.NoSuchScreenHandler</value>
<value>com.haulmont.cuba.web.exception.DeletePolicyHandler</value>
<value>com.haulmont.cuba.web.exception.NumericOverflowExceptionHandler</value>
<value>com.haulmont.cuba.web.exception.OptimisticExceptionHandler</value>
<value>com.haulmont.cuba.web.exception.ReportExceptionHandler</value>
<value>com.haulmont.cuba.web.exception.FileMissingExceptionHandler</value>
<value>com.haulmont.cuba.web.exception.InvalidValueExceptionHandler</value>
<value>com.haulmont.cuba.web.exception.EntityDeletedExceptionHandler</value>
</list>
</property>
</bean>
<!-- Spring scheduling setup -->
<bean id="scheduler" class="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler">
<property name="daemon" value="true"/>
@ -87,7 +108,7 @@
<task:scheduled ref="cuba_FileUploading" method="clearTempDirectory" cron="0 0 0 * * 2,4,6"/>
</task:scheduled-tasks>
<!-- Background Tasks -->
<!-- Background tasks support -->
<bean id="cuba_BackgroundWorker_WatchDog" class="com.haulmont.cuba.gui.executors.TasksWatchDog"/>
@ -95,19 +116,4 @@
<constructor-arg index="0" ref="cuba_BackgroundWorker_WatchDog"/>
</bean>
<!--
For use BackgroundWorker in project add to {app}-web-spring.xml this sheduler definition:
<bean id="backgroundWorkerScheduler" class="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler">
<property name="daemon" value="true"/>
<property name="poolSize" value="1"/>
</bean>
<task:scheduled-tasks scheduler="backgroundWorkerScheduler">
<task:scheduled ref="cuba_BackgroundWorker_WatchDog" method="cleanupTasks" fixed-delay="2000"/>
</task:scheduled-tasks>
-->
</beans>