View Javadoc
1   package fr.ifremer.quadrige3.ui.swing.action;
2   
3   /*-
4    * #%L
5    * Quadrige3 Core :: Quadrige3 UI Common
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2017 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU Affero General Public License as published by
13   * the Free Software Foundation, either version 3 of the License, or
14   * (at your option) any later version.
15   *
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   *
21   * You should have received a copy of the GNU Affero General Public License
22   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23   * #L%
24   */
25  
26  import fr.ifremer.quadrige3.core.dao.technical.Assert;
27  import fr.ifremer.quadrige3.core.exception.QuadrigeTechnicalException;
28  import fr.ifremer.quadrige3.ui.swing.AbstractUIHandler;
29  import fr.ifremer.quadrige3.ui.swing.ApplicationUIContext;
30  import org.apache.commons.lang3.reflect.ConstructorUtils;
31  import org.nuiton.i18n.I18n;
32  import org.nuiton.jaxx.application.swing.AbstractApplicationUIHandler;
33  import org.nuiton.jaxx.application.swing.action.AbstractApplicationAction;
34  import org.nuiton.jaxx.application.swing.action.ApplicationActionFactory;
35  
36  import javax.swing.AbstractButton;
37  import java.util.concurrent.*;
38  
39  /**
40   * Action Factory
41   */
42  public class ActionFactory extends ApplicationActionFactory {
43  
44      /**
45       * {@inheritDoc}
46       */
47      @Override
48      public <A extends AbstractApplicationAction> A createLogicAction(AbstractApplicationUIHandler handler, Class<A> actionName) {
49          ApplicationUIContext context = (ApplicationUIContext) handler.getContext();
50          if (AbstractMainUIAction.class.isAssignableFrom(actionName) && context.getMainUI() != null) {
51              handler = context.getMainUI().getHandler();
52          }
53  
54          return super.createLogicAction(handler, actionName);
55      }
56  
57      /**
58       * <p>createNonBlockingUIAction.</p>
59       *
60       * @param handler    a {@link AbstractUIHandler} object.
61       * @param actionName a {@link Class} object.
62       * @param <A>        a A object.
63       * @return a A object.
64       */
65      public <A extends AbstractWorkerAction> A createNonBlockingUIAction(AbstractUIHandler handler, Class<A> actionName) {
66          return createNonBlockingUIAction(handler, actionName, null);
67      }
68  
69      /**
70       * <p>createNonBlockingUIAction.</p>
71       *
72       * @param handler    a {@link AbstractUIHandler} object.
73       * @param actionName a {@link Class} object.
74       * @param button     a {@link AbstractButton} object.
75       * @param <A>        a A object.
76       * @return a A object.
77       */
78      public <A extends AbstractWorkerAction> A createNonBlockingUIAction(AbstractUIHandler handler, Class<A> actionName, AbstractButton button) {
79          try {
80              // create action
81              A action = ConstructorUtils.invokeConstructor(actionName, handler);
82  
83              if (button != null) {
84                  action.setActionIcon(button.getIcon());
85                  action.setActionName(button.getText());
86                  action.setActionDescription(button.getToolTipText());
87                  action.setActionMnemonic(button.getMnemonic());
88              }
89  
90              return action;
91          } catch (Exception e) {
92              throw new QuadrigeTechnicalException(I18n.t("quadrige3.error.create.action", actionName.getName()), e);
93          }
94  
95      }
96  
97      public enum ExecutionMode {
98          UNIQUE,
99          CUMULATIVE,
100         LATEST
101     }
102 
103     /**
104      * Create a ThreadPoolExecutor with pool active option
105      *
106      * @param executionMode value of the mode of execution:<br/>
107      *                      UNIQUE : create an executor allowing only one execution. An exception is raised if a second call happens.<br/>
108      *                      CUMULATIVE : create a poolable executor allowing cumulative calls but reject silently the other calls.<br/>
109      *                      LATEST: create a (scheduled) poolable executor allowing multiple calls but always executes the last (after a short delay). Useful for UI interactions.<br/>
110      * @return a ThreadPoolExecutor
111      */
112     public static ThreadPoolExecutor createSingleThreadExecutor(ExecutionMode executionMode) {
113 
114         Assert.notNull(executionMode);
115 
116         if (executionMode == ExecutionMode.LATEST) {
117 
118             return new ScheduledThreadPoolExecutor(1) {
119                 @Override
120                 public void execute(Runnable command) {
121 
122                     getQueue().forEach(runnable -> {
123                         if (runnable instanceof Future<?>) {
124                             ((Future<?>) runnable).cancel(false);
125                         }
126                     });
127 
128                     schedule(command, 200, TimeUnit.MILLISECONDS);
129                 }
130             };
131 
132         } else {
133 
134             RejectedExecutionHandler rejectedExecutionHandler = null;
135             int queueCapacity = 0;
136             switch (executionMode) {
137                 case UNIQUE:
138                     rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy();
139                     queueCapacity = 1;
140                     break;
141                 case CUMULATIVE:
142                     rejectedExecutionHandler = new ThreadPoolExecutor.DiscardPolicy();
143                     queueCapacity = 2;
144                     break;
145             }
146 
147             Assert.notNull(rejectedExecutionHandler);
148             BlockingQueue<Runnable> queue = new LinkedBlockingDeque<>(queueCapacity);
149             return new ThreadPoolExecutor(1, 1, 1, TimeUnit.MINUTES, queue, rejectedExecutionHandler);
150         }
151     }
152 }