View Javadoc
1   package com.jsql.view.swing.panel.address;
2   
3   import com.jsql.model.injection.strategy.AbstractStrategy;
4   import com.jsql.model.injection.strategy.StrategyError;
5   import com.jsql.model.injection.vendor.model.Vendor;
6   import com.jsql.model.injection.vendor.model.yaml.Method;
7   import com.jsql.util.I18nUtil;
8   import com.jsql.util.LogLevelUtil;
9   import com.jsql.view.swing.panel.PanelAddressBar;
10  import com.jsql.view.swing.text.JToolTipI18n;
11  import com.jsql.view.swing.util.I18nViewUtil;
12  import com.jsql.view.swing.util.MediatorHelper;
13  import com.jsql.view.swing.util.UiUtil;
14  import org.apache.logging.log4j.LogManager;
15  import org.apache.logging.log4j.Logger;
16  
17  import javax.swing.*;
18  import java.awt.*;
19  import java.awt.event.MouseAdapter;
20  import java.awt.event.MouseEvent;
21  import java.util.Arrays;
22  import java.util.Locale;
23  import java.util.concurrent.atomic.AtomicReference;
24  import java.util.stream.StreamSupport;
25  
26  public class PanelTrailingAddress extends JPanel {
27  
28      private static final Logger LOGGER = LogManager.getRootLogger();
29  
30      private JMenu itemRadioStrategyError;
31  
32      private final JLabel labelVendor = new JLabel(UiUtil.ARROW_DOWN.getIcon(), SwingConstants.LEFT);
33      private final JLabel labelStrategy = new JLabel(UiUtil.ARROW_DOWN.getIcon(), SwingConstants.LEFT);
34      private final JPopupMenu popupMenuVendors = new JPopupMenu();
35      private final JPopupMenu popupMenuStrategies = new JPopupMenu();
36  
37      private final ButtonGroup groupStrategy = new ButtonGroup();
38      private static final String PREFIX_NAME_ERROR = "itemRadioError";
39      private static final String I18N_TOOLTIP_STRATEGY = "STRATEGY_%s_TOOLTIP";
40  
41      /**
42       * Loader displayed during injection.
43       */
44      private final JProgressBar loader;
45  
46      /**
47       * Connection button.
48       */
49      public final ButtonStart buttonStart = new ButtonStart();
50      
51      public PanelTrailingAddress(PanelAddressBar panelAddressBar) {
52          this.buttonStart.addActionListener(new ActionStart(panelAddressBar));
53          this.setOpaque(false);
54          this.setBorder(null);
55          this.labelStrategy.setText("Strategy auto");
56          this.labelStrategy.setName("menuStrategy");
57  
58          for (final AbstractStrategy strategy: MediatorHelper.model().getMediatorStrategy().getStrategies()) {
59              var nameStrategy = strategy.getName().toUpperCase(Locale.ROOT);
60              JMenuItem itemRadioStrategy;
61              if (strategy == MediatorHelper.model().getMediatorStrategy().getError()) {
62                  itemRadioStrategy = new JMenu(strategy.toString());
63                  this.itemRadioStrategyError = (JMenu) itemRadioStrategy;
64                  itemRadioStrategy.getComponent().setName("itemRadioStrategyError");
65              } else {
66                  var atomicTooltip = new AtomicReference<>(new JToolTipI18n(
67                      I18nUtil.valueByKey(String.format(PanelTrailingAddress.I18N_TOOLTIP_STRATEGY, nameStrategy))
68                  ));
69                  itemRadioStrategy = new JRadioButtonMenuItem(strategy.toString()) {
70                      @Override
71                      public JToolTip createToolTip() {
72                          atomicTooltip.set(new JToolTipI18n(
73                              I18nUtil.valueByKey(
74                                  String.format(PanelTrailingAddress.I18N_TOOLTIP_STRATEGY, nameStrategy)
75                              )
76                          ));
77                          return atomicTooltip.get();
78                      }
79                  };
80                  I18nViewUtil.addComponentForKey(
81                      String.format(PanelTrailingAddress.I18N_TOOLTIP_STRATEGY, nameStrategy),
82                      atomicTooltip.get()
83                  );
84                  itemRadioStrategy.getComponent().setName("itemRadioStrategy" + strategy);
85                  itemRadioStrategy.addActionListener(actionEvent -> {
86                      this.labelStrategy.setText(strategy.toString());
87                      MediatorHelper.model().getMediatorStrategy().setStrategy(strategy);
88                  });
89                  this.groupStrategy.add(itemRadioStrategy);
90              }
91  
92              this.popupMenuStrategies.add(itemRadioStrategy);
93              itemRadioStrategy.setToolTipText(
94                  I18nUtil.valueByKey(String.format(PanelTrailingAddress.I18N_TOOLTIP_STRATEGY, nameStrategy))
95              );
96              itemRadioStrategy.setEnabled(false);
97          }
98  
99          this.labelVendor.setText(MediatorHelper.model().getMediatorVendor().getAuto().toString());
100         this.labelVendor.setName("menuVendor");
101         this.popupMenuVendors.setLayout(UiUtil.getColumnLayout(MediatorHelper.model().getMediatorVendor().getVendors().size()));
102         var groupVendor = new ButtonGroup();
103         for (final Vendor vendor: MediatorHelper.model().getMediatorVendor().getVendors()) {
104             JMenuItem itemRadioVendor = new JRadioButtonMenuItem(vendor.toString(), vendor == MediatorHelper.model().getMediatorVendor().getAuto());
105             itemRadioVendor.setName("itemRadioVendor"+ vendor);
106             itemRadioVendor.addActionListener(actionEvent -> {
107                 this.labelVendor.setText(vendor.toString());
108                 MediatorHelper.model().getMediatorVendor().setVendorByUser(vendor);
109             });
110             this.popupMenuVendors.add(itemRadioVendor);
111             groupVendor.add(itemRadioVendor);
112         }
113 
114         this.loader = new JProgressBar();
115         var dimension = UIManager.getDimension("ProgressBar.horizontalSize");
116         this.loader.setPreferredSize(new Dimension(32, dimension.height));
117         this.loader.setIndeterminate(true);
118         this.add(this.loader);
119 
120         this.labelVendor.addMouseListener(new MouseAdapter() {
121             @Override
122             public void mousePressed(MouseEvent e) {
123                 Arrays.stream(PanelTrailingAddress.this.popupMenuVendors.getComponents())
124                     .map(JComponent.class::cast)
125                     .forEach(JComponent::updateUI);  // required: incorrect when dark/light mode switch
126                 PanelTrailingAddress.this.popupMenuVendors.updateUI();  // required: incorrect when dark/light mode switch
127                 PanelTrailingAddress.this.popupMenuVendors.show(e.getComponent(), e.getComponent().getX(),5 + e.getComponent().getY() + e.getComponent().getHeight());
128                 PanelTrailingAddress.this.popupMenuVendors.setLocation(e.getComponent().getLocationOnScreen().x,5 + e.getComponent().getLocationOnScreen().y + e.getComponent().getHeight());
129             }
130         });
131         this.labelStrategy.addMouseListener(new MouseAdapter() {
132             @Override
133             public void mousePressed(MouseEvent e) {
134                 Arrays.stream(PanelTrailingAddress.this.popupMenuStrategies.getComponents()).map(a -> (JComponent) a).forEach(JComponent::updateUI);  // required: incorrect when dark/light mode switch
135                 for (var i = 0 ; i < PanelTrailingAddress.this.getMenuError().getItemCount() ; i++) {
136                     PanelTrailingAddress.this.getMenuError().getItem(i).updateUI();  // required: incorrect when dark/light mode switch
137                 }
138                 PanelTrailingAddress.this.popupMenuStrategies.updateUI();  // required: incorrect when dark/light mode switch
139                 PanelTrailingAddress.this.popupMenuStrategies.show(e.getComponent(), e.getComponent().getX(),5 + e.getComponent().getY() + e.getComponent().getHeight());
140                 PanelTrailingAddress.this.popupMenuStrategies.setLocation(e.getComponent().getLocationOnScreen().x,5 + e.getComponent().getLocationOnScreen().y + e.getComponent().getHeight());
141             }
142         });
143 
144         this.add(this.labelVendor);
145         this.add(this.labelStrategy);
146         this.add(this.buttonStart);
147         this.setCursor(Cursor.getDefaultCursor());
148         this.loader.setVisible(false);
149     }
150 
151     public void endPreparation() {
152         this.buttonStart.setToolTipText(I18nUtil.valueByKey("BUTTON_START_TOOLTIP"));
153         this.buttonStart.setInjectionReady();
154         this.loader.setVisible(false);
155     }
156     
157     public void reset() {
158         this.labelStrategy.setText("Strategy auto");
159         if (MediatorHelper.model().getMediatorVendor().getVendorByUser() == MediatorHelper.model().getMediatorVendor().getAuto()) {
160             this.labelVendor.setText(MediatorHelper.model().getMediatorVendor().getAuto().toString());
161         }
162         Arrays.stream(this.popupMenuStrategies.getComponents())
163             .forEach(component -> component.setEnabled(false));
164         this.getMenuError().removeAll();
165 
166         this.groupStrategy.clearSelection();
167         Iterable<AbstractButton> iterable = () -> this.groupStrategy.getElements().asIterator();
168         StreamSupport.stream(iterable.spliterator(), false)
169             .filter(abstractButton -> abstractButton.getName().startsWith(PanelTrailingAddress.PREFIX_NAME_ERROR))
170             .forEach(this.groupStrategy::remove);
171     }
172     
173     public void setVendor(Vendor vendor) {
174         this.labelVendor.setText(vendor.toString());
175         this.itemRadioStrategyError.removeAll();
176         var indexError = 0;
177         if (
178             vendor != MediatorHelper.model().getMediatorVendor().getAuto()
179             && vendor.instance().getModelYaml().getStrategy().getError() != null
180         ) {
181             for (Method methodError: vendor.instance().getModelYaml().getStrategy().getError().getMethod()) {
182                 JMenuItem itemRadioError = new JRadioButtonMenuItem(methodError.getName());
183                 itemRadioError.setEnabled(false);
184                 itemRadioError.setName(PanelTrailingAddress.PREFIX_NAME_ERROR + methodError.getName());
185                 this.itemRadioStrategyError.add(itemRadioError);
186                 this.groupStrategy.add(itemRadioError);
187                 int indexErrorFinal = indexError;
188                 itemRadioError.addActionListener(actionEvent -> {
189                     this.labelStrategy.setText(methodError.getName());
190                     MediatorHelper.model().getMediatorStrategy().setStrategy(MediatorHelper.model().getMediatorStrategy().getError());
191                     MediatorHelper.model().getMediatorStrategy().getError().setIndexErrorStrategy(indexErrorFinal);
192                 });
193                 indexError++;
194             }
195         }
196     }
197     
198     public void markStrategy(AbstractStrategy strategy) {
199         this.labelStrategy.setText(strategy.toString());
200         Arrays.stream(this.popupMenuStrategies.getComponents())
201             .map(JMenuItem.class::cast)
202             .filter(jMenuItem -> jMenuItem.getText().equals(strategy.toString()))
203             .forEach(jMenuItem -> jMenuItem.setSelected(true));
204     }
205     
206     public void markStrategyInvulnerable(AbstractStrategy strategy) {
207         Arrays.stream(this.popupMenuStrategies.getComponents())
208             .map(JMenuItem.class::cast)
209             .filter(jMenuItem -> jMenuItem.getText().equals(strategy.toString()))
210             .forEach(jMenuItem -> jMenuItem.setEnabled(false));
211     }
212     
213     public void markErrorInvulnerable(int indexMethodError) {
214         AbstractStrategy strategy = MediatorHelper.model().getMediatorStrategy().getError();
215         Arrays.stream(this.popupMenuStrategies.getSubElements())
216             .map(JMenuItem.class::cast)
217             .filter(jMenuItem -> jMenuItem.getText().equals(strategy.toString()))
218             .map(JMenu.class::cast)
219             .filter(jMenuItem -> {
220                 var isNotNull = true;
221                 // Fix #36975: ArrayIndexOutOfBoundsException on getItem()
222                 // Fix #40352: NullPointerException on ?
223                 // Fix #95855: NPE on setEnabled()
224                 try {
225                     isNotNull = jMenuItem.getItem(indexMethodError) != null;
226                 } catch (ArrayIndexOutOfBoundsException e) {
227                     LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
228                     return false;
229                 }
230                 return isNotNull;
231             })
232             .forEach(jMenuItem -> jMenuItem.getItem(indexMethodError).setEnabled(false));
233     }
234     
235     public void markError() {
236         StrategyError strategy = MediatorHelper.model().getMediatorStrategy().getError();
237         this.labelStrategy.setText(strategy.toString());
238         int indexError = strategy.getIndexErrorStrategy();
239         String nameError = MediatorHelper.model().getMediatorVendor().getVendor().instance().getModelYaml().getStrategy().getError().getMethod().get(indexError).getName();
240 
241         Arrays.stream(this.getMenuError().getMenuComponents())
242             .map(JRadioButtonMenuItem.class::cast)
243             .filter(component -> component.getText().equals(nameError))
244             .forEach(jRadioButtonMenuItem -> {
245                 jRadioButtonMenuItem.setSelected(true);
246                 this.labelStrategy.setText(nameError);
247             });
248     }
249 
250     private JMenu getMenuError() {
251         var nameError = MediatorHelper.model().getMediatorStrategy().getError().getName();
252         return (JMenu) Arrays.stream(this.popupMenuStrategies.getComponents())
253             .map(JMenuItem.class::cast)
254             .filter(jMenuItem -> jMenuItem.getText().equalsIgnoreCase(nameError))
255             .findFirst()
256             .orElse(new JMenuItem("Mock"));
257     }
258 
259     public void markErrorVulnerable(int indexMethodError) {
260         AbstractStrategy strategy = MediatorHelper.model().getMediatorStrategy().getError();
261         // Fix #46578: ArrayIndexOutOfBoundsException on getItem()
262         try {
263             Arrays.stream(this.popupMenuStrategies.getComponents())
264                 .map(JMenuItem.class::cast)
265                 .filter(jMenuItem -> jMenuItem.getText().equals(strategy.toString()))
266                 .map(JMenu.class::cast)
267                 .filter(jMenuItem -> jMenuItem.getItem(indexMethodError) != null)
268                 .forEach(jMenuItem -> {
269                     jMenuItem.setEnabled(true);
270                     jMenuItem.getItem(indexMethodError).setEnabled(true);
271                 });
272         } catch (ArrayIndexOutOfBoundsException e) {
273             LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
274         }
275     }
276     
277     public void markStrategyVulnerable(AbstractStrategy strategy) {
278         Arrays.stream(this.popupMenuStrategies.getComponents())
279             .map(JMenuItem.class::cast)
280             .filter(jMenuItem -> jMenuItem.getText().equals(strategy.toString()))
281             .forEach(jMenuItem -> jMenuItem.setEnabled(true));
282     }
283     
284     
285     // Getter and setter
286 
287     public JComponent getLoader() {
288         return this.loader;
289     }
290 
291     public ButtonStart getButtonStart() {
292         return this.buttonStart;
293     }
294 }