UI uncaught exceptions handling

This commit is contained in:
Konstantin Krivopustov 2008-12-16 12:08:03 +00:00
parent 77971c6932
commit febd2fc680
8 changed files with 270 additions and 4 deletions

View File

@ -13,6 +13,7 @@ package com.haulmont.cuba.web;
import com.haulmont.cuba.security.global.UserSession; import com.haulmont.cuba.security.global.UserSession;
import com.haulmont.cuba.web.config.MenuConfig; import com.haulmont.cuba.web.config.MenuConfig;
import com.haulmont.cuba.web.ScreenManager; import com.haulmont.cuba.web.ScreenManager;
import com.haulmont.cuba.web.log.AppLog;
import com.haulmont.cuba.web.config.ActionConfig; import com.haulmont.cuba.web.config.ActionConfig;
import com.itmill.toolkit.Application; import com.itmill.toolkit.Application;
import com.itmill.toolkit.terminal.Terminal; import com.itmill.toolkit.terminal.Terminal;
@ -37,6 +38,8 @@ public class App extends Application implements ConnectionListener
private ScreenManager screenManager; private ScreenManager screenManager;
private AppLog appLog;
private static ThreadLocal<App> currentApp = new ThreadLocal<App>(); private static ThreadLocal<App> currentApp = new ThreadLocal<App>();
static { static {
@ -44,6 +47,7 @@ public class App extends Application implements ConnectionListener
} }
public App() { public App() {
appLog = new AppLog();
connection = new Connection(); connection = new Connection();
connection.addListener(this); connection.addListener(this);
screenManager = new ScreenManager(this); screenManager = new ScreenManager(this);
@ -91,12 +95,21 @@ public class App extends Application implements ConnectionListener
return screenManager; return screenManager;
} }
public AppLog getAppLog() {
return appLog;
}
public void connectionStateChanged(Connection connection) { public void connectionStateChanged(Connection connection) {
if (!connection.isConnected()) { if (!connection.isConnected()) {
menuConfig = null; menuConfig = null;
} }
} }
public void terminalError(Terminal.ErrorEvent event) {
super.terminalError(event);
getAppLog().log(event);
}
private class RequestListener implements ApplicationContext.TransactionListener private class RequestListener implements ApplicationContext.TransactionListener
{ {
public void transactionStart(Application application, Object transactionData) { public void transactionStart(Application application, Object transactionData) {

View File

@ -10,9 +10,9 @@
*/ */
package com.haulmont.cuba.web; package com.haulmont.cuba.web;
import com.itmill.toolkit.ui.*; import com.haulmont.cuba.web.log.LogWindow;
import com.haulmont.cuba.web.Navigator;
import com.haulmont.cuba.web.resource.Messages; import com.haulmont.cuba.web.resource.Messages;
import com.itmill.toolkit.ui.*;
import java.util.Locale; import java.util.Locale;
@ -77,12 +77,24 @@ public class AppWindow extends Window implements ConnectionListener
); );
logoutBtn.setStyleName(Button.STYLE_LINK); logoutBtn.setStyleName(Button.STYLE_LINK);
Button viewLogBtn = new Button(Messages.getString("viewLogBtn"),
new Button.ClickListener()
{
public void buttonClick(Button.ClickEvent event) {
LogWindow logWindow = new LogWindow();
addWindow(logWindow);
}
}
);
viewLogBtn.setStyleName(Button.STYLE_LINK);
ExpandLayout titleLayout = new ExpandLayout(ExpandLayout.ORIENTATION_HORIZONTAL); ExpandLayout titleLayout = new ExpandLayout(ExpandLayout.ORIENTATION_HORIZONTAL);
titleLayout.setSpacing(true); titleLayout.setSpacing(true);
titleLayout.setHeight(-1); titleLayout.setHeight(-1);
titleLayout.addComponent(navBtn); titleLayout.addComponent(navBtn);
titleLayout.addComponent(label); titleLayout.addComponent(label);
titleLayout.addComponent(logoutBtn); titleLayout.addComponent(logoutBtn);
titleLayout.addComponent(viewLogBtn);
titleLayout.expand(navBtn); titleLayout.expand(navBtn);
rootLayout.addComponent(titleLayout); rootLayout.addComponent(titleLayout);

View File

@ -12,6 +12,7 @@ package com.haulmont.cuba.web;
import com.haulmont.cuba.web.App; import com.haulmont.cuba.web.App;
import com.haulmont.cuba.web.ScreenOpenType; import com.haulmont.cuba.web.ScreenOpenType;
import com.haulmont.cuba.web.log.LogLevel;
import com.haulmont.cuba.web.config.ScreenAction; import com.haulmont.cuba.web.config.ScreenAction;
import com.haulmont.cuba.web.ui.Screen; import com.haulmont.cuba.web.ui.Screen;
import com.haulmont.cuba.web.ui.ScreenTitlePane; import com.haulmont.cuba.web.ui.ScreenTitlePane;
@ -50,6 +51,7 @@ public class ScreenManager
} }
public Screen openScreen(ScreenOpenType type, String actionName, String tabCaption) { public Screen openScreen(ScreenOpenType type, String actionName, String tabCaption) {
app.getAppLog().debug("Opening screen " + actionName);
ScreenAction action = app.getActionConfig().getAction(actionName); ScreenAction action = app.getActionConfig().getAction(actionName);
if (tabCaption == null) if (tabCaption == null)
tabCaption = action.getCaption(); tabCaption = action.getCaption();
@ -106,7 +108,7 @@ public class ScreenManager
TabInfo tabInfo = tabs.get(layout); TabInfo tabInfo = tabs.get(layout);
if (tabInfo == null) if (tabInfo == null)
throw new IllegalStateException("Current tab not found"); throw new IllegalStateException("Unable to close screen: current tab not found");
Screen screen = tabInfo.screens.getLast(); Screen screen = tabInfo.screens.getLast();
if (!screen.onClose()) { if (!screen.onClose()) {

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2008 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
* Author: Konstantin Krivopustov
* Created: 16.12.2008 11:09:01
*
* $Id$
*/
package com.haulmont.cuba.web.log;
import com.itmill.toolkit.terminal.ParameterHandler;
import com.itmill.toolkit.terminal.Terminal;
import com.itmill.toolkit.terminal.URIHandler;
import com.itmill.toolkit.terminal.VariableOwner;
import com.itmill.toolkit.terminal.gwt.server.ChangeVariablesErrorEvent;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class AppLog
{
private LinkedList<LogItem> items = new LinkedList<LogItem>();
private int capacity = 100;
public void log(LogItem item) {
if (items.size() >= capacity) {
items.removeLast();
}
items.addFirst(item);
}
public void log(LogLevel level, String message, Throwable throwable) {
log(new LogItem(level, message, throwable));
}
public void debug(String message) {
log(new LogItem(LogLevel.DEBUG, message, null));
}
public void info(String message) {
log(new LogItem(LogLevel.INFO, message, null));
}
public void warning(String message) {
log(new LogItem(LogLevel.WARNING, message, null));
}
public void error(String message) {
log(new LogItem(LogLevel.ERROR, message, null));
}
public void log(Terminal.ErrorEvent event) {
Throwable t = event.getThrowable();
if (t instanceof SocketException) {
// Most likely client browser closed socket
LogItem item = new LogItem(LogLevel.WARNING, "SocketException in CommunicationManager. Most likely client (browser) closed socket.", null);
log(item);
return;
}
// Finds the original source of the error/exception
Object owner = null;
if (event instanceof VariableOwner.ErrorEvent) {
owner = ((VariableOwner.ErrorEvent) event).getVariableOwner();
} else if (event instanceof URIHandler.ErrorEvent) {
owner = ((URIHandler.ErrorEvent) event).getURIHandler();
} else if (event instanceof ParameterHandler.ErrorEvent) {
owner = ((ParameterHandler.ErrorEvent) event).getParameterHandler();
} else if (event instanceof ChangeVariablesErrorEvent) {
owner = ((ChangeVariablesErrorEvent) event).getComponent();
}
StringBuilder msg = new StringBuilder();
if (owner != null)
msg.append("[").append(owner.getClass().getName()).append("] ");
msg.append("Uncaught throwable:");
LogItem item = new LogItem(LogLevel.ERROR, msg.toString(), t);
log(item);
}
public List<LogItem> getItems() {
return new ArrayList<LogItem>(items);
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2008 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
* Author: Konstantin Krivopustov
* Created: 16.12.2008 11:09:18
*
* $Id$
*/
package com.haulmont.cuba.web.log;
import com.haulmont.cuba.core.global.TimeProvider;
import java.util.Date;
public class LogItem
{
private Date timestamp;
private LogLevel level;
private String message;
private Throwable throwable;
public LogItem(LogLevel level, String message, Throwable throwable) {
this.timestamp = TimeProvider.currentTimestamp();
this.level = level;
this.message = message;
this.throwable = throwable;
}
public LogLevel getLevel() {
return level;
}
public String getMessage() {
return message;
}
public Throwable getThrowable() {
return throwable;
}
public Date getTimestamp() {
return timestamp;
}
}

View File

@ -0,0 +1,19 @@
/*
* Copyright (c) 2008 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
* Author: Konstantin Krivopustov
* Created: 16.12.2008 11:26:19
*
* $Id$
*/
package com.haulmont.cuba.web.log;
public enum LogLevel
{
DEBUG,
INFO,
WARNING,
ERROR
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2008 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
* Author: Konstantin Krivopustov
* Created: 16.12.2008 12:01:45
*
* $Id$
*/
package com.haulmont.cuba.web.log;
import com.itmill.toolkit.ui.Window;
import com.itmill.toolkit.ui.Label;
import com.itmill.toolkit.ui.Button;
import com.itmill.toolkit.ui.ExpandLayout;
import com.haulmont.cuba.web.resource.Messages;
import com.haulmont.cuba.web.App;
import java.util.List;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
public class LogWindow extends Window
{
private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
public LogWindow() {
super(Messages.getString("logWindow.caption"));
setHeight("80%");
setWidth("80%");
initUI();
}
private void initUI() {
ExpandLayout layout = new ExpandLayout(ExpandLayout.ORIENTATION_VERTICAL);
layout.setSpacing(true);
setLayout(layout);
final Label label = new Label();
label.setContentMode(Label.CONTENT_UIDL);
label.setValue(writeLog());
Button refreshBtn = new Button(Messages.getString("logWindow.refreshBtn"),
new Button.ClickListener()
{
public void buttonClick(Button.ClickEvent event) {
label.setValue(writeLog());
}
}
);
addComponent(refreshBtn);
addComponent(label);
layout.expand(label);
}
private String writeLog() {
List<LogItem> items = App.getInstance().getAppLog().getItems();
StringBuilder sb = new StringBuilder();
for (LogItem item : items) {
sb.append("<b>");
sb.append(DateFormatUtils.format(item.getTimestamp(), DATE_FORMAT));
sb.append(" ");
sb.append(item.getLevel().name());
sb.append("</b> ");
sb.append(item.getMessage());
if (item.getThrowable() != null) {
sb.append(" ");
sb.append(ExceptionUtils.getStackTrace(item.getThrowable()).replace("\n", "<br>"));
}
sb.append("<br>");
}
return sb.toString();
}
}

View File

@ -9,9 +9,16 @@ action-config.sec$Role.browse=Browse Roles
action-config.sec$User.browse=Browse Users action-config.sec$User.browse=Browse Users
application.caption=Cuba Application application.caption=Cuba Application
welcomeLabel=Hello from Cuba! welcomeLabel=Hello from Cuba!
navBtn=Navigator navBtn=Navigator
logoutBtn=Logout logoutBtn=Logout
loggedInLabel=Logged in as %s loggedInLabel=Logged in as %s
viewLogBtn=View Log
closeBtn=Close
navigator.caption=Navigator navigator.caption=Navigator
closeBtn=Close
logWindow.caption=Application Log
logWindow.refreshBtn=Refresh