/* * This library is part of OpenCms - * the Open Source Content Management System * * Copyright (c) Alkacon Software GmbH (http://www.alkacon.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * For further information about Alkacon Software, please see the * company website: http://www.alkacon.com * * For further information about OpenCms, please see the * project website: http://www.opencms.org * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.opencms.gwt.client.rpc; import org.opencms.gwt.CmsRpcException; import org.opencms.gwt.client.Messages; import org.opencms.gwt.client.ui.CmsErrorDialog; import org.opencms.gwt.client.ui.CmsNotification; import org.opencms.gwt.client.util.CmsClientStringUtil; import com.google.gwt.event.shared.UmbrellaException; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.rpc.AsyncCallback; /** * Consistently manages RPCs errors and 'loading' state.<p> * * @param <T> The type of the expected return value * * @since 8.0 */ public abstract class CmsRpcAction<T> implements AsyncCallback<T> { /** The message displayed when loading. */ private String m_loadingMessage = Messages.get().key(Messages.GUI_LOADING_0); /** The result, used only for synchronized request. */ private T m_result; /** The timer to control the display of the 'loading' state, if the action takes too long. */ private Timer m_timer; /** * Executes the current RPC call.<p> * * Initializes client-server communication and will */ public abstract void execute(); /** * Executes a synchronized request.<p> * * @return the RPC result * * @see #execute() */ public T executeSync() { execute(); return m_result; } /** * Handle errors.<p> * * @see com.google.gwt.user.client.rpc.AsyncCallback#onFailure(java.lang.Throwable) */ public void onFailure(Throwable t) { String message; StackTraceElement[] trace; if (t instanceof CmsRpcException) { CmsRpcException ex = (CmsRpcException)t; message = ex.getOriginalMessage(); trace = ex.getOriginalStackTrace(); } else { message = CmsClientStringUtil.getMessage(t); trace = t.getStackTrace(); } // send the ticket to the server String ticket = CmsLog.log(message + "\n" + CmsClientStringUtil.getStackTraceAsString(trace, "\n")); // remove the overlay stop(false); provideFeedback(ticket, t); } /** * @see com.google.gwt.user.client.rpc.AsyncCallback#onSuccess(java.lang.Object) */ public void onSuccess(T value) { try { m_result = value; onResponse(value); } catch (UmbrellaException exception) { Throwable wrappedException = exception.getCauses().iterator().next(); onFailure(wrappedException); } catch (RuntimeException error) { onFailure(error); } } /** * Sets the loading message.<p> * * @param loadingMessage the loading message to set */ public void setLoadingMessage(String loadingMessage) { m_loadingMessage = loadingMessage; } /** * Starts the timer for showing the 'loading' state.<p> * * Note: Has to be called manually before calling the RPC service.<p> * * @param delay the delay in milliseconds * @param blocking shows an blocking overlay if <code>true</code> */ public void start(int delay, final boolean blocking) { if (delay <= 0) { show(blocking); return; } m_timer = new Timer() { /** * @see com.google.gwt.user.client.Timer#run() */ @Override public void run() { show(blocking); } }; m_timer.schedule(delay); } /** * Stops the timer.<p> * * Note: Has to be called manually on success.<p> * * @param displayDone <code>true</code> if you want to tell the user that the operation was successful */ public void stop(boolean displayDone) { if (m_timer != null) { m_timer.cancel(); m_timer = null; } CmsNotification.get().hide(); if (displayDone) { CmsNotification.get().send(CmsNotification.Type.NORMAL, Messages.get().key(Messages.GUI_DONE_0)); } } /** * Handles the result when received from server.<p> * * @param result the result from server * * @see AsyncCallback#onSuccess(Object) */ protected abstract void onResponse(T result); /** * Provides some feedback to the user in case of failure.<p> * * @param ticket the generated ticket * @param throwable the thrown error */ protected void provideFeedback(String ticket, Throwable throwable) { String message; String cause = null; String className; StackTraceElement[] trace; if (throwable instanceof CmsRpcException) { CmsRpcException ex = (CmsRpcException)throwable; message = ex.getOriginalMessage(); cause = ex.getOriginalCauseMessage(); className = ex.getOriginalClassName(); trace = ex.getOriginalStackTrace(); } else { message = CmsClientStringUtil.getMessage(throwable); if (throwable.getCause() != null) { cause = CmsClientStringUtil.getMessage(throwable.getCause()); } className = throwable.getClass().getName(); trace = throwable.getStackTrace(); } String lineBreak = "<br />\n"; String errorMessage = message == null ? className + ": " + Messages.get().key(Messages.GUI_NO_DESCIPTION_0) : message; if (cause != null) { errorMessage += lineBreak + Messages.get().key(Messages.GUI_REASON_0) + ":" + cause; } String details = Messages.get().key(Messages.GUI_TICKET_MESSAGE_3, ticket, className, message) + CmsClientStringUtil.getStackTraceAsString(trace, lineBreak); new CmsErrorDialog(errorMessage, details).center(); } /** * Shows the 'loading message'.<p> * * Overwrite to customize the message.<p> * * @param blocking shows an blocking overlay if <code>true</code> */ protected void show(boolean blocking) { if (blocking) { CmsNotification.get().sendBlocking(CmsNotification.Type.NORMAL, m_loadingMessage); } else { CmsNotification.get().sendSticky(CmsNotification.Type.NORMAL, m_loadingMessage); } } }