package ilarkesto.ui.action; import ilarkesto.base.Str; import ilarkesto.concurrent.ATask; import ilarkesto.core.logging.Log; import ilarkesto.di.BeanProvider; import ilarkesto.form.Form; import ilarkesto.form.validator.Validator; import ilarkesto.id.CountingIdGenerator; import ilarkesto.id.IdGenerator; import ilarkesto.locale.Localizer; import ilarkesto.persistence.DaoService; import ilarkesto.persistence.TransactionService; import ilarkesto.ui.AUi; import ilarkesto.ui.AView; import ilarkesto.ui.DialogTimeoutException; import ilarkesto.ui.Option; import java.util.Collection; import java.util.Set; public abstract class AAction extends ATask { private static final Log LOG = Log.get(AAction.class); private static final IdGenerator actionIdGenerator = new CountingIdGenerator(""); protected abstract void assertPermissions() throws InterruptedException; protected abstract void performAction() throws InterruptedException; private volatile boolean finished; private volatile Throwable exception; @Override public final void perform() { ActionPerformer.registerAction(this); try { assertPermissions(); performAction(); } catch (InterruptedException ex) { finish(); return; } catch (ActionAbortedException ex) { transactionService.commit(); exception = ex; if (isRootAction() && !ui.isViewSet()) showReturnView(); finish(); return; } catch (Throwable ex) { transactionService.commit(); exception = ex; LOG.error(ex); error(ex); if (isRootAction() && !ui.isViewSet()) showReturnView(); finish(); return; } transactionService.commit(); if (!infoDisplayed && autoShowInfoDone) infoDone(); if (!ui.isViewSet() && isRootAction()) showReturnView(); finish(); } private void finish() { finished = true; ActionPerformer.unregisterAction(getActionId()); synchronized (this) { notifyAll(); } } protected final void showReturnView() { String viewId = getReturnViewId(); if (viewId.startsWith("entity:")) { ui.showView(daoService.getEntityById(viewId.substring(7)), null); return; } ui.showView(viewId, null); } public final boolean isActionFinished() { return finished; } public final Throwable getException() { return exception; } protected AAction parentAction; public final AAction getParentAction() { return parentAction; } private final boolean isRootAction() { return parentAction == null; } public final void setParentAction(AAction action) { this.parentAction = action; } @Override public String toString() { return getClass().getSimpleName(); } // -------------- // --- helper --- // -------------- protected String getReturnViewId() { if (returnToView != null) { if (isViewIdValid(returnToView)) return returnToView; } return "overview"; // TODO replace string } private final boolean isViewIdValid(String viewId) { if (viewId == null) return false; if ("option".equals(viewId)) return false; return true; } protected final <T> T autowire(T bean) { return beanProvider.autowire(bean); } // --- action --- protected final <A extends AAction> A createAction(Class<A> actionClass) { try { return beanProvider.autowire(actionClass.newInstance()); } catch (Throwable ex) { throw new RuntimeException(ex); } } protected final void performAction(AAction action) { actionPerformer.performSubAction(action, this); } // --- ui --- protected final void showDialog(Class<? extends AView> view) throws InterruptedException { try { ui.showDialog(view, this, this); } catch (DialogTimeoutException ex) { throw new ActionAbortedException(ex.getMessage()); } } protected final void showDialog(Form form) throws InterruptedException { try { ui.showDialog("simpleForm", this, this); } catch (DialogTimeoutException ex) { throw new ActionAbortedException(ex.getMessage()); } } protected final <T> void showDialog(Collection<Option<T>> options, String message) throws InterruptedException { try { ui.showDialog("option", this, this); } catch (DialogTimeoutException ex) { throw new ActionAbortedException(ex.getMessage()); } } // --- inputAction --- protected final String showInputDialog() { return showInputDialog(getStringKeyPrefix(), null); } protected final String showInputDialog(String stringKeyPrefix, Validator validator) { InputAction action = beanProvider.autowire(new InputAction()); action.setValidator(validator); action.setStringKeyPrefix(stringKeyPrefix); actionPerformer.performSubAction(action, this); return action.getInputString(); } // --- optionAction --- protected final void showConfirmDialog(Object... messageParameters) { showOptionDialog("confirm", messageParameters); } protected final String showOptionDialog(String name, Object[] messageParameters, String... options) { if (options == null || options.length == 0) options = new String[] { "ok" }; OptionAction<String> action = autowire(new OptionAction()); action.setMessage(string(name + ".message", messageParameters)); action.setHorizontal(true); for (String option : options) { action.addOption(new Option<String>(option, string(name + "." + option), option, option)); } actionPerformer.performSubAction(action, this); return action.getSelectedPayload(); } protected final <T> T showOptionDialog(String messageString, Collection<T> optionPayloads) { return OptionAction.showDialog(beanProvider, actionPerformer, this, string(messageString), optionPayloads); } protected final <T> Set<T> showMultiOptionDialog(String messageString, Collection<T> optionPayloads) { return MultiOptionAction.showDialog(beanProvider, actionPerformer, this, string(messageString), optionPayloads); } protected final <F extends Form> FormAction<F> showFormDialog(F form) { FormAction<F> action = new FormAction<F>(); action.setForm(form); actionPerformer.performSubAction(action, this); return action; } // --- strings --- private String stringKeyPrefix; public void setStringKeyPrefix(String stringKeyPrefix) { this.stringKeyPrefix = stringKeyPrefix; } protected String getStringKeyPrefix() { return stringKeyPrefix != null ? stringKeyPrefix : getStringKey(getClass()); } protected final String string(String key, Object... parameters) { return ui.getLocalizer().string(getStringKeyPrefix() + "." + key, parameters); } // --- user messages --- protected boolean infoDisplayed; protected final void infoDone(Object... parameters) { info("done", parameters); } protected final void info(String key, Object... parameters) { infoDisplayed = true; ui.getUserMessageService().info(string("info." + key, parameters)); } protected final void error(Throwable t) { error("exception", Str.format(t)); } protected final void error(String key, Object... parameters) { infoDisplayed = true; ui.getUserMessageService().error(string("error." + key, parameters)); } protected final String getReturnToView() { return returnToView; } // ------------------ // --- model data --- // ------------------ public final String getResponseActionId() { return actionId; } // -------------------- // --- dependencies --- // -------------------- protected TransactionService transactionService; public final void setTransactionService(TransactionService transactionService) { this.transactionService = transactionService; } protected DaoService daoService; public final void setDaoService(DaoService daoService) { this.daoService = daoService; } private String actionId; public final String getActionId() { if (actionId == null) { actionId = actionIdGenerator.generateId() + "Action"; } return actionId; } protected boolean autoShowInfoDone = true; public final void setAutoShowInfoDone(boolean autoShowInfoDone) { this.autoShowInfoDone = autoShowInfoDone; } protected ActionPerformer actionPerformer; public void setActionPerformer(ActionPerformer actionPerformer) { this.actionPerformer = actionPerformer; } private AUi ui; public AUi getUi() { return ui; } public final void setUi(AUi ui) { this.ui = ui; } protected Localizer localizer; public final void setLocalizer(Localizer localizer) { this.localizer = localizer; } protected BeanProvider beanProvider; public final void setBeanProvider(BeanProvider beanProvider) { this.beanProvider = beanProvider; } private String returnToView; public final void setReturnToView(String returnToView) { this.returnToView = returnToView; } // ------------- // --- utils --- // ------------- public static String getStringKey(Class<? extends AAction> actionClass) { return actionClass.getSimpleName(); } }