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