001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2008-2010 Sun Microsystems, Inc.
015 * Portions Copyright 2014-2016 ForgeRock AS.
016 */
017package org.opends.guitools.controlpanel.ui;
018
019import static com.forgerock.opendj.cli.Utils.*;
020
021import static org.opends.messages.AdminToolMessages.*;
022
023import java.awt.Component;
024import java.awt.GridBagConstraints;
025import java.awt.GridBagLayout;
026import java.util.ArrayList;
027import java.util.Collection;
028import java.util.List;
029
030import javax.swing.JLabel;
031import javax.swing.JPanel;
032import javax.swing.JScrollPane;
033import javax.swing.JTextArea;
034import javax.swing.JTextField;
035import javax.swing.event.ChangeEvent;
036import javax.swing.event.ChangeListener;
037import javax.swing.text.JTextComponent;
038
039import org.forgerock.i18n.LocalizableMessage;
040import org.forgerock.opendj.ldap.DN;
041import org.opends.guitools.controlpanel.datamodel.BackendDescriptor;
042import org.opends.guitools.controlpanel.datamodel.BaseDNDescriptor;
043import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
044import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
045import org.opends.guitools.controlpanel.task.Task;
046import org.opends.guitools.controlpanel.ui.components.BasicExpander;
047import org.opends.guitools.controlpanel.util.Utilities;
048import org.opends.server.protocols.ldap.LDAPFilter;
049import org.opends.server.types.LDAPException;
050
051/** Abstract class used to refactor some code used by the import LDIF and export LDIF panels. */
052public abstract class InclusionExclusionPanel extends StatusGenericPanel
053{
054  private static final long serialVersionUID = -3826176895778069011L;
055  /** The DNs to exclude. */
056  private JTextArea dnsToExclude;
057  /** The attributes to exclude. */
058  private JTextField attributesToExclude;
059  /** The exclusion filter. */
060  private JTextField exclusionFilter;
061  /** The DNs to include. */
062  private JTextArea dnsToInclude;
063  /** The attributes to include. */
064  private JTextField attributesToInclude;
065  /** The inclusion filter. */
066  private JTextField inclusionFilter;
067
068  /** The DNs to include. */
069  private JLabel lDnsToInclude;
070  /** The attributes to include. */
071  private JLabel lAttributesToInclude;
072  /** The inclusion filter label. */
073  private JLabel lInclusionFilter;
074  /** The DNs to exclude label. */
075  private JLabel lDnsToExclude;
076  /** The attributes to exclude label. */
077  private JLabel lAttributesToExclude;
078  /** The exclusion filter label. */
079  private JLabel lExclusionFilter;
080
081  @Override
082  public void cancelClicked()
083  {
084    setPrimaryValid(lDnsToInclude);
085    setPrimaryValid(lAttributesToInclude);
086    setPrimaryValid(lInclusionFilter);
087    setPrimaryValid(lDnsToExclude);
088    setPrimaryValid(lAttributesToExclude);
089    setPrimaryValid(lExclusionFilter);
090    super.cancelClicked();
091  }
092
093  /**
094   * A commodity method that layouts a set of components.
095   * @param extraComponentLabels the labels.
096   * @param extraComponents the components.
097   * @return the panel containing the labels and the components.
098   */
099  protected Component createDataInclusionOptions(
100      final JLabel[] extraComponentLabels,
101      final Component[] extraComponents)
102  {
103    JPanel panel = new JPanel(new GridBagLayout());
104    panel.setOpaque(false);
105    GridBagConstraints gbc = new GridBagConstraints();
106    gbc.weightx = 1.0;
107    gbc.gridwidth = 2;
108    gbc.gridx = 0;
109    gbc.gridy = 0;
110    gbc.anchor = GridBagConstraints.NORTHWEST;
111    gbc.fill = GridBagConstraints.HORIZONTAL;
112    int labelInsetLeft = 15;
113    final BasicExpander expander =
114      new BasicExpander(INFO_CTRL_PANEL_DATA_INCLUSION_OPTIONS.get());
115    panel.add(expander, gbc);
116
117    gbc.gridy ++;
118    lDnsToInclude =
119      Utilities.createPrimaryLabel(INFO_CTRL_PANEL_DNS_TO_INCLUDE.get());
120    gbc.insets.left = labelInsetLeft;
121    gbc.anchor = GridBagConstraints.NORTHWEST;
122    gbc.insets.top = 10;
123    gbc.gridwidth = 1;
124    gbc.weightx = 0.0;
125    panel.add(lDnsToInclude, gbc);
126
127    gbc.gridx = 1;
128    gbc.weightx = 1.0;
129    gbc.insets.left = 10;
130    dnsToInclude = Utilities.createTextArea(LocalizableMessage.EMPTY, 5, 25);
131    final JScrollPane scrollDns = Utilities.createScrollPane(dnsToInclude);
132    panel.add(scrollDns, gbc);
133    lDnsToInclude.setLabelFor(dnsToInclude);
134
135    gbc.insets.top = 2;
136    gbc.gridy ++;
137    final JLabel lDnsExplanation = Utilities.createInlineHelpLabel(
138        INFO_CTRL_PANEL_SEPARATE_DNS_LINE_BREAK.get());
139    panel.add(lDnsExplanation, gbc);
140
141    gbc.gridy ++;
142    gbc.gridx = 0;
143    gbc.weightx = 0.0;
144    lAttributesToInclude = Utilities.createPrimaryLabel(
145        INFO_CTRL_PANEL_ATTRIBUTES_TO_INCLUDE.get());
146    gbc.insets.left = labelInsetLeft;
147    gbc.anchor = GridBagConstraints.NORTHWEST;
148    gbc.insets.top = 10;
149    gbc.gridwidth = 1;
150    panel.add(lAttributesToInclude, gbc);
151
152    gbc.gridx = 1;
153    gbc.weightx = 1.0;
154    gbc.insets.left = 10;
155    gbc.weightx = 1.0;
156    attributesToInclude = Utilities.createMediumTextField();
157    panel.add(attributesToInclude, gbc);
158    lAttributesToInclude.setLabelFor(attributesToInclude);
159
160    gbc.insets.top = 2;
161    gbc.gridy ++;
162    final JLabel lAttributesExplanation = Utilities.createInlineHelpLabel(
163        INFO_CTRL_PANEL_SEPARATE_ATTRIBUTES_COMMA.get());
164    panel.add(lAttributesExplanation, gbc);
165
166    gbc.gridy ++;
167    gbc.gridx = 0;
168    lInclusionFilter = Utilities.createPrimaryLabel(
169        INFO_CTRL_PANEL_INCLUSION_FILTER.get());
170    gbc.insets.left = labelInsetLeft;
171    gbc.anchor = GridBagConstraints.NORTHWEST;
172    gbc.insets.top = 10;
173    gbc.gridwidth = 1;
174    gbc.weightx = 0.0;
175    panel.add(lInclusionFilter, gbc);
176
177    gbc.gridx = 1;
178    gbc.weightx = 1.0;
179    gbc.insets.left = 10;
180    inclusionFilter = Utilities.createMediumTextField();
181    panel.add(inclusionFilter, gbc);
182    lInclusionFilter.setLabelFor(inclusionFilter);
183
184    addExtraComponents(panel, extraComponentLabels, extraComponents, gbc,
185        labelInsetLeft);
186
187    ChangeListener changeListener = new ChangeListener()
188    {
189      @Override
190      public void stateChanged(ChangeEvent e)
191      {
192        lDnsToInclude.setVisible(expander.isSelected());
193        scrollDns.setVisible(expander.isSelected());
194        lDnsExplanation.setVisible(expander.isSelected());
195        lAttributesToInclude.setVisible(expander.isSelected());
196        attributesToInclude.setVisible(expander.isSelected());
197        lAttributesExplanation.setVisible(expander.isSelected());
198        lInclusionFilter.setVisible(expander.isSelected());
199        inclusionFilter.setVisible(expander.isSelected());
200        expanderStateChanged(expander, extraComponentLabels, extraComponents);
201      }
202    };
203    expander.addChangeListener(changeListener);
204    expander.setSelected(false);
205    changeListener.stateChanged(null);
206
207    return panel;
208  }
209
210  /**
211   * A commodity method that layouts a set of components.
212   * @param extraComponentLabels the labels.
213   * @param extraComponents the components.
214   * @return the panel containing the labels and the components.
215   */
216  protected Component createDataExclusionOptions(
217      final JLabel[] extraComponentLabels,
218      final Component[] extraComponents)
219  {
220    JPanel panel = new JPanel(new GridBagLayout());
221    panel.setOpaque(false);
222    GridBagConstraints gbc = new GridBagConstraints();
223    gbc.weightx = 1.0;
224    gbc.gridwidth = 2;
225    gbc.gridx = 0;
226    gbc.gridy = 0;
227    gbc.anchor = GridBagConstraints.NORTHWEST;
228    gbc.fill = GridBagConstraints.HORIZONTAL;
229    int labelInsetLeft = 15;
230    final BasicExpander expander =
231      new BasicExpander(INFO_CTRL_PANEL_DATA_EXCLUSION_OPTIONS.get());
232    panel.add(expander, gbc);
233
234    gbc.gridy ++;
235    lDnsToExclude =
236      Utilities.createPrimaryLabel(INFO_CTRL_PANEL_DNS_TO_EXCLUDE.get());
237    gbc.insets.left = labelInsetLeft;
238    gbc.anchor = GridBagConstraints.NORTHWEST;
239    gbc.insets.top = 10;
240    gbc.gridwidth = 1;
241    gbc.weightx = 0.0;
242    panel.add(lDnsToExclude, gbc);
243
244    gbc.gridx = 1;
245    gbc.weightx = 1.0;
246    gbc.insets.left = 10;
247    dnsToExclude = Utilities.createTextArea(LocalizableMessage.EMPTY, 5, 0);
248    final JScrollPane scrollDns = Utilities.createScrollPane(dnsToExclude);
249    lDnsToExclude.setLabelFor(dnsToExclude);
250    panel.add(scrollDns, gbc);
251
252    gbc.insets.top = 2;
253    gbc.gridy ++;
254    final JLabel lDnsExplanation = Utilities.createInlineHelpLabel(
255        INFO_CTRL_PANEL_SEPARATE_DNS_LINE_BREAK.get());
256    panel.add(lDnsExplanation, gbc);
257
258    gbc.gridy ++;
259    gbc.gridx = 0;
260    gbc.weightx = 0.0;
261    lAttributesToExclude = Utilities.createPrimaryLabel(
262        INFO_CTRL_PANEL_ATTRIBUTES_TO_EXCLUDE.get());
263    gbc.insets.left = labelInsetLeft;
264    gbc.anchor = GridBagConstraints.NORTHWEST;
265    gbc.insets.top = 10;
266    gbc.gridwidth = 1;
267    panel.add(lAttributesToExclude, gbc);
268
269    gbc.gridx = 1;
270    gbc.weightx = 1.0;
271    gbc.insets.left = 10;
272    gbc.weightx = 1.0;
273    attributesToExclude = Utilities.createTextField();
274    panel.add(attributesToExclude, gbc);
275    lAttributesToExclude.setLabelFor(dnsToExclude);
276
277    gbc.insets.top = 2;
278    gbc.gridy ++;
279    final JLabel lAttributesExplanation = Utilities.createInlineHelpLabel(
280        INFO_CTRL_PANEL_SEPARATE_ATTRIBUTES_COMMA.get());
281    panel.add(lAttributesExplanation, gbc);
282    lAttributesExplanation.setLabelFor(dnsToExclude);
283
284    gbc.gridy ++;
285    gbc.gridx = 0;
286    lExclusionFilter = Utilities.createPrimaryLabel(
287        INFO_CTRL_PANEL_EXCLUSION_FILTER.get());
288    gbc.insets.left = labelInsetLeft;
289    gbc.anchor = GridBagConstraints.NORTHWEST;
290    gbc.insets.top = 10;
291    gbc.gridwidth = 1;
292    gbc.weightx = 0.0;
293    panel.add(lExclusionFilter, gbc);
294
295    gbc.gridx = 1;
296    gbc.weightx = 1.0;
297    gbc.insets.left = 10;
298    exclusionFilter = Utilities.createTextField();
299    panel.add(exclusionFilter, gbc);
300    lExclusionFilter.setLabelFor(exclusionFilter);
301
302    addExtraComponents(panel, extraComponentLabels, extraComponents, gbc,
303        labelInsetLeft);
304
305    ChangeListener changeListener = new ChangeListener()
306    {
307      @Override
308      public void stateChanged(ChangeEvent e)
309      {
310        lDnsToExclude.setVisible(expander.isSelected());
311        scrollDns.setVisible(expander.isSelected());
312        lDnsExplanation.setVisible(expander.isSelected());
313        lAttributesToExclude.setVisible(expander.isSelected());
314        attributesToExclude.setVisible(expander.isSelected());
315        lAttributesExplanation.setVisible(expander.isSelected());
316        lExclusionFilter.setVisible(expander.isSelected());
317        exclusionFilter.setVisible(expander.isSelected());
318        expanderStateChanged(expander, extraComponentLabels, extraComponents);
319      }
320    };
321    expander.addChangeListener(changeListener);
322    expander.setSelected(false);
323    changeListener.stateChanged(null);
324
325    return panel;
326  }
327
328  private void addExtraComponents(JPanel panel, JLabel[] extraComponentLabels,
329      Component[] extraComponents, GridBagConstraints gbc, int labelInsetLeft)
330  {
331    for (int i=0; i<extraComponentLabels.length; i++)
332    {
333      gbc.gridy ++;
334      gbc.gridx = 0;
335      gbc.insets.left = labelInsetLeft;
336      gbc.anchor = GridBagConstraints.NORTHWEST;
337      gbc.insets.top = 10;
338
339      if (extraComponentLabels[i] == null)
340      {
341        gbc.gridwidth = 2;
342        gbc.weightx = 1.0;
343        panel.add(extraComponents[i], gbc);
344      }
345      else
346      {
347        gbc.gridwidth = 1;
348        gbc.weightx = 0.0;
349        panel.add(extraComponentLabels[i], gbc);
350
351        gbc.gridx = 1;
352        gbc.weightx = 1.0;
353        gbc.insets.left = 10;
354        panel.add(extraComponents[i], gbc);
355
356        extraComponentLabels[i].setLabelFor(extraComponents[i]);
357      }
358    }
359  }
360
361  private void expanderStateChanged(BasicExpander expander,
362      JLabel[] extraComponentLabels,
363      Component[] extraComponents)
364  {
365    for (JLabel comp : extraComponentLabels)
366    {
367      if (comp != null)
368      {
369        comp.setVisible(expander.isSelected());
370      }
371    }
372    for (Component comp : extraComponents)
373    {
374      comp.setVisible(expander.isSelected());
375    }
376  }
377
378
379  /**
380   * Updates a list of errors in the include and exclude subpanels.
381   * @param errors the list of errors to be updated.
382   * @param backendName the name of the backend where the operation associated
383   * with the panel applies (used to generate the error messages).
384   */
385  protected void updateIncludeExclude(Collection<LocalizableMessage> errors,
386      String backendName)
387  {
388    updateErrors(lDnsToInclude, dnsToInclude, lAttributesToInclude,
389        attributesToInclude, lInclusionFilter, inclusionFilter, errors,
390        backendName);
391    updateErrors(lDnsToExclude, dnsToExclude, lAttributesToExclude,
392        attributesToExclude, lExclusionFilter, exclusionFilter, errors,
393        backendName);
394  }
395
396
397  private void updateErrors(JLabel lDns, JTextComponent dns, JLabel lAttributes,
398      JTextComponent attributes, JLabel lFilter, JTextComponent filter,
399      Collection<LocalizableMessage> errors, String backendName)
400  {
401    setPrimaryValid(lDns);
402    setPrimaryValid(lAttributes);
403    setPrimaryValid(lFilter);
404
405    String s = dns.getText();
406
407    boolean validDn = true;
408
409    if (s.trim().length() > 0)
410    {
411      String[] dnArray = s.split("\n");
412      for (int i=0; i<dnArray.length; i++)
413      {
414        if (!isDN(dnArray[i]))
415        {
416          errors.add(ERR_CTRL_PANEL_DN_NOT_VALID_WITH_VALUE.get(dnArray[i]));
417          validDn = false;
418        }
419        else
420        {
421          BackendDescriptor backend = null;
422
423          if (backendName != null)
424          {
425            ServerDescriptor server = getInfo().getServerDescriptor();
426            for (BackendDescriptor b : server.getBackends())
427            {
428              if (b.getBackendID().equalsIgnoreCase(backendName))
429              {
430                backend = b;
431                break;
432              }
433            }
434          }
435
436          if (backend != null)
437          {
438            boolean found = false;
439            for (BaseDNDescriptor baseDN : backend.getBaseDns())
440            {
441              try
442              {
443                DN dn = DN.valueOf(dnArray[i]);
444                if (dn.isSubordinateOrEqualTo(baseDN.getDn()))
445                {
446                  found = true;
447                  break;
448                }
449              }
450              catch (Throwable t)
451              {
452                // Bug
453                t.printStackTrace();
454              }
455            }
456            if (!found)
457            {
458              errors.add(ERR_CTRL_PANEL_NOT_A_DESCENDANT_OF_BASE_DN.get(
459                  dnArray[i], backendName));
460            }
461          }
462        }
463      }
464    }
465
466    if (!validDn)
467    {
468      setPrimaryInvalid(lDns);
469    }
470
471    s = attributes.getText();
472
473    boolean validAttributes = true;
474
475    if (s.trim().length() > 0)
476    {
477      String[] attributeArray = s.split(",");
478      for (int i=0; i<attributeArray.length; i++)
479      {
480        if (!Utilities.isValidAttributeName(attributeArray[i]))
481        {
482          errors.add(ERR_CTRL_PANEL_NOT_VALID_ATTRIBUTE_NAME.get(
483              attributeArray[i]));
484          validAttributes = false;
485        }
486      }
487    }
488
489    if (!validAttributes)
490    {
491      setPrimaryInvalid(lAttributes);
492    }
493
494    s = filter.getText();
495    if (s != null && s.trim().length() > 0)
496    {
497      try
498      {
499        LDAPFilter.decode(s);
500      }
501      catch (LDAPException le)
502      {
503        errors.add(ERR_CTRL_PANEL_INVALID_FILTER_DETAILS_WITH_VALUE.get(s, le.getMessageObject()));
504        setPrimaryInvalid(lFilter);
505      }
506    }
507  }
508
509  /**
510   * Abstract class that provides some methods that can be used to generate the
511   * equivalent command-line arguments for some of the things that are contained
512   * in the inclusion/exclusion panels.
513   */
514  protected abstract class InclusionExclusionTask extends Task
515  {
516    /**
517     * The constructor of the task.
518     * @param info the control panel info.
519     * @param dlg the progress dialog that shows the progress of the task.
520     */
521    protected InclusionExclusionTask(ControlPanelInfo info, ProgressDialog dlg)
522    {
523      super(info, dlg);
524    }
525
526    /**
527     * Returns the command line arguments corresponding to the elements
528     * displayed in the inclusion/exclusion panels.
529     * @return the command line arguments corresponding to the elements
530     * displayed in the inclusion/exclusion panels.
531     */
532    @Override
533    protected List<String> getCommandLineArguments()
534    {
535      List<String> args = new ArrayList<>();
536      String s = dnsToInclude.getText();
537      if (s.trim().length() > 0)
538      {
539        String[] dnArray = s.split("\n");
540        for (String dn : dnArray)
541        {
542          args.add("--includeBranch");
543          args.add(dn);
544        }
545      }
546      s = attributesToInclude.getText();
547      if (s.trim().length() > 0)
548      {
549        String[] attrArray = s.split(",");
550        for (String attr : attrArray)
551        {
552          args.add("--includeAttribute");
553          args.add(attr);
554        }
555      }
556      s = inclusionFilter.getText();
557      if (s.trim().length() > 0)
558      {
559        args.add("--includeFilter");
560        args.add(s);
561      }
562
563      s = dnsToExclude.getText();
564      if (s.trim().length() > 0)
565      {
566        String[] dnArray = s.split("\n");
567        for (String dn : dnArray)
568        {
569          args.add("--excludeBranch");
570          args.add(dn);
571        }
572      }
573      s = attributesToExclude.getText();
574      if (s.trim().length() > 0)
575      {
576        String[] attrArray = s.split(",");
577        for (String attr : attrArray)
578        {
579          args.add("--excludeAttribute");
580          args.add(attr);
581        }
582      }
583      s = exclusionFilter.getText();
584      if (s.trim().length() > 0)
585      {
586        args.add("--excludeFilter");
587        args.add(s);
588      }
589      args.addAll(getConnectionCommandLineArguments());
590      return args;
591    }
592  }
593}