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