1 /*
   2  * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package anttasks;
  27 
  28 import java.awt.GridBagConstraints;
  29 import java.awt.GridBagLayout;
  30 import java.awt.event.ActionEvent;
  31 import java.awt.event.ActionListener;
  32 import java.awt.event.FocusEvent;
  33 import java.awt.event.FocusListener;
  34 import java.awt.event.ItemEvent;
  35 import java.awt.event.ItemListener;
  36 import java.io.BufferedReader;
  37 import java.io.BufferedWriter;
  38 import java.io.File;
  39 import java.io.FileReader;
  40 import java.io.FileWriter;
  41 import java.io.IOException;
  42 import java.io.Reader;
  43 import java.io.Writer;
  44 import java.util.EnumSet;
  45 import java.util.Properties;
  46 
  47 import javax.swing.JButton;
  48 import javax.swing.JCheckBox;
  49 import javax.swing.JComboBox;
  50 import javax.swing.JDialog;
  51 import javax.swing.JLabel;
  52 import javax.swing.JOptionPane;
  53 import javax.swing.JPanel;
  54 import javax.swing.JTextField;
  55 
  56 import javax.swing.SwingUtilities;
  57 
  58 import org.apache.tools.ant.BuildException;
  59 import org.apache.tools.ant.Project;
  60 import org.apache.tools.ant.Task;
  61 
  62 /**
  63  * Task to allow the user to control langtools tools built when using NetBeans.
  64  *
  65  * There are two primary modes.
  66  * 1) Property mode. In this mode, property names are provided to get values
  67  * that may be specified by the user, either directly in a GUI dialog, or
  68  * read from a properties file. If the GUI dialog is invoked, values may
  69  * optionally be set for future use.
  70  * 2) Setup mode. In this mode, no property names are provided, and the GUI
  71  * is invoked to allow the user to set or reset values for use in property mode.
  72  */
  73 public class SelectToolTask extends Task {
  74 
  75     enum ToolChoices {
  76         NONE(""),
  77         JAVAC("javac"),
  78         JAVADOC("javadoc"),
  79         JAVAP("javap"),
  80         JSHELL("jshell");
  81 
  82         String toolName;
  83         boolean bootstrap;
  84 
  85         ToolChoices(String toolName) {
  86             this(toolName, false);
  87         }
  88 
  89         ToolChoices(String toolName, boolean bootstrap) {
  90             this.toolName = toolName;
  91             this.bootstrap = bootstrap;
  92         }
  93 
  94         @Override
  95         public String toString() {
  96             return toolName;
  97         }
  98     }
  99 
 100     /**
 101      * Set the location of the private properties file used to keep the retain
 102      * user preferences for this repository.
 103      * @param propertyFile the private properties file
 104      */
 105     public void setPropertyFile(File propertyFile) {
 106         this.propertyFile = propertyFile;
 107     }
 108 
 109     /**
 110      * Set the name of the property which will be set to the name of the
 111      * selected tool, if any. If no tool is selected, the property will
 112      * remain unset.
 113      * @param toolProperty the tool name property
 114      */
 115     public void setToolProperty(String toolProperty) {
 116         this.toolProperty = toolProperty;
 117     }
 118 
 119     /**
 120      * Set the name of the property which will be set to the execution args of the
 121      * selected tool, if any. The args default to an empty string.
 122      * @param argsProperty the execution args property value
 123      */
 124     public void setArgsProperty(String argsProperty) {
 125         this.argsProperty = argsProperty;
 126     }
 127 
 128     /**
 129      * Specify whether or not to pop up a dialog if the user has not specified
 130      * a default value for a property.
 131      * @param askIfUnset a boolean flag indicating to prompt the user or not
 132      */
 133     public void setAskIfUnset(boolean askIfUnset) {
 134         this.askIfUnset = askIfUnset;
 135     }
 136 
 137     @Override
 138     public void execute() {
 139         Project p = getProject();
 140 
 141         Properties props = readProperties(propertyFile);
 142         toolName = props.getProperty("tool.name");
 143         if (toolName != null) {
 144             toolArgs = props.getProperty(toolName + ".args", "");
 145         }
 146 
 147         if (toolProperty == null ||
 148             askIfUnset && (toolName == null
 149                 || (argsProperty != null && toolArgs == null))) {
 150             showGUI(props);
 151         }
 152 
 153         // finally, return required values, if any
 154         if (toolProperty != null && !(toolName == null || toolName.equals(""))) {
 155             p.setProperty(toolProperty, toolName);
 156 
 157             if (argsProperty != null && toolArgs != null)
 158                 p.setProperty(argsProperty, toolArgs);
 159         }
 160     }
 161 
 162     void showGUI(Properties fileProps) {
 163         Properties guiProps = new Properties(fileProps);
 164         JOptionPane p = createPane(guiProps);
 165         p.createDialog("Select Tool").setVisible(true);
 166 
 167         ToolChoices tool = (ToolChoices)toolChoice.getSelectedItem();
 168 
 169         toolName = tool.toolName;
 170         toolArgs = argsField.getText();
 171         if (defaultCheck.isSelected()) {
 172             if (toolName.equals("")) {
 173                 fileProps.remove("tool.name");
 174                 fileProps.remove("tool.bootstrap");
 175             } else {
 176                 fileProps.remove("tool.bootstrap");
 177                 fileProps.put("tool.name", toolName);
 178                 fileProps.put(toolName + ".args", toolArgs);
 179             }
 180             writeProperties(propertyFile, fileProps);
 181         }
 182     }
 183 
 184     JOptionPane createPane(final Properties props) {
 185         JPanel body = new JPanel(new GridBagLayout());
 186         GridBagConstraints lc = new GridBagConstraints();
 187         lc.insets.right = 10;
 188         lc.insets.bottom = 3;
 189         GridBagConstraints fc = new GridBagConstraints();
 190         fc.gridx = 1;
 191         fc.gridwidth = GridBagConstraints.NONE;
 192         fc.insets.bottom = 3;
 193 
 194         JPanel toolPane = new JPanel(new GridBagLayout());
 195 
 196         JLabel toolLabel = new JLabel("Tool:");
 197         body.add(toolLabel, lc);
 198         EnumSet<ToolChoices> toolChoices = toolProperty == null ?
 199                 EnumSet.allOf(ToolChoices.class) : EnumSet.range(ToolChoices.JAVAC, ToolChoices.JAVAP);
 200         toolChoice = new JComboBox<>(toolChoices.toArray());
 201         ToolChoices tool = toolName != null ? ToolChoices.valueOf(toolName.toUpperCase()) : null;
 202         if (toolName != null) {
 203             toolChoice.setSelectedItem(tool);
 204         }
 205         toolChoice.addItemListener(e -> {
 206             ToolChoices tool1 = (ToolChoices)e.getItem();
 207             argsField.setText(getDefaultArgsForTool(props, tool1));
 208             if (toolProperty != null)
 209                 okButton.setEnabled(tool1 != ToolChoices.NONE);
 210         });
 211         fc.anchor = GridBagConstraints.EAST;
 212 
 213         GridBagConstraints toolConstraint = new GridBagConstraints();
 214         fc.anchor = GridBagConstraints.WEST;
 215 
 216         toolPane.add(toolChoice, toolConstraint);
 217 
 218         body.add(toolPane, fc);
 219 
 220         argsField = new JTextField(getDefaultArgsForTool(props, tool), 40);
 221         if (toolProperty == null || argsProperty != null) {
 222             JLabel argsLabel = new JLabel("Args:");
 223             body.add(argsLabel, lc);
 224             body.add(argsField, fc);
 225             argsField.addFocusListener(new FocusListener() {
 226                 @Override
 227                 public void focusGained(FocusEvent e) {
 228                 }
 229                 @Override
 230                 public void focusLost(FocusEvent e) {
 231                     String toolName = ((ToolChoices)toolChoice.getSelectedItem()).toolName;
 232                     if (toolName.length() > 0)
 233                         props.put(toolName + ".args", argsField.getText());
 234                 }
 235             });
 236         }
 237 
 238         defaultCheck = new JCheckBox("Set as default");
 239         if (toolProperty == null)
 240             defaultCheck.setSelected(true);
 241         else
 242             body.add(defaultCheck, fc);
 243 
 244         final JOptionPane p = new JOptionPane(body);
 245         okButton = new JButton("OK");
 246         okButton.setEnabled(toolProperty == null || (toolName != null && !toolName.equals("")));
 247         okButton.addActionListener(e -> {
 248             JDialog d = (JDialog) SwingUtilities.getAncestorOfClass(JDialog.class, p);
 249             d.setVisible(false);
 250         });
 251         p.setOptions(new Object[] { okButton });
 252 
 253         return p;
 254     }
 255 
 256     Properties readProperties(File file) {
 257         Properties p = new Properties();
 258         if (file != null && file.exists()) {
 259             Reader in = null;
 260             try {
 261                 in = new BufferedReader(new FileReader(file));
 262                 p.load(in);
 263                 in.close();
 264             } catch (IOException e) {
 265                 throw new BuildException("error reading property file", e);
 266             } finally {
 267                 if (in != null) {
 268                     try {
 269                         in.close();
 270                     } catch (IOException e) {
 271                         throw new BuildException("cannot close property file", e);
 272                     }
 273                 }
 274             }
 275         }
 276         return p;
 277     }
 278 
 279     void writeProperties(File file, Properties p) {
 280         if (file != null) {
 281             Writer out = null;
 282             try {
 283                 File dir = file.getParentFile();
 284                 if (dir != null && !dir.exists())
 285                     dir.mkdirs();
 286                 out = new BufferedWriter(new FileWriter(file));
 287                 p.store(out, "langtools properties");
 288                 out.close();
 289             } catch (IOException e) {
 290                 throw new BuildException("error writing property file", e);
 291             } finally {
 292                 if (out != null) {
 293                     try {
 294                         out.close();
 295                     } catch (IOException e) {
 296                         throw new BuildException("cannot close property file", e);
 297                     }
 298                 }
 299             }
 300         }
 301     }
 302 
 303     String getDefaultArgsForTool(Properties props, ToolChoices tool) {
 304         if (tool == null)
 305             return "";
 306         String toolName = tool.toolName;
 307         return toolName.equals("") ? "" : props.getProperty(toolName + ".args", "");
 308     }
 309 
 310     // Ant task parameters
 311     private boolean askIfUnset;
 312     private String toolProperty;
 313     private String argsProperty;
 314     private File propertyFile;
 315 
 316     // GUI components
 317     private JComboBox<?> toolChoice;
 318     private JTextField argsField;
 319     private JCheckBox defaultCheck;
 320     private JButton okButton;
 321 
 322     // Result values for the client
 323     private String toolName;
 324     private String toolArgs;
 325 }