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         JAVAH("javah"),
  80         JAVAP("javap"),
  81         JSHELL("jshell");
  82 
  83         String toolName;
  84         boolean bootstrap;
  85 
  86         ToolChoices(String toolName) {
  87             this(toolName, false);
  88         }
  89 
  90         ToolChoices(String toolName, boolean bootstrap) {
  91             this.toolName = toolName;
  92             this.bootstrap = bootstrap;
  93         }
  94 
  95         @Override
  96         public String toString() {
  97             return toolName;
  98         }
  99     }
 100 
 101     /**
 102      * Set the location of the private properties file used to keep the retain
 103      * user preferences for this repository.
 104      * @param propertyFile the private properties file
 105      */
 106     public void setPropertyFile(File propertyFile) {
 107         this.propertyFile = propertyFile;
 108     }
 109 
 110     /**
 111      * Set the name of the property which will be set to the name of the
 112      * selected tool, if any. If no tool is selected, the property will
 113      * remain unset.
 114      * @param toolProperty the tool name property
 115      */
 116     public void setToolProperty(String toolProperty) {
 117         this.toolProperty = toolProperty;
 118     }
 119 
 120     /**
 121      * Set the name of the property which will be set to the execution args of the
 122      * selected tool, if any. The args default to an empty string.
 123      * @param argsProperty the execution args property value
 124      */
 125     public void setArgsProperty(String argsProperty) {
 126         this.argsProperty = argsProperty;
 127     }
 128 
 129     /**
 130      * Specify whether or not to pop up a dialog if the user has not specified
 131      * a default value for a property.
 132      * @param askIfUnset a boolean flag indicating to prompt the user or not
 133      */
 134     public void setAskIfUnset(boolean askIfUnset) {
 135         this.askIfUnset = askIfUnset;
 136     }
 137 
 138     @Override
 139     public void execute() {
 140         Project p = getProject();
 141 
 142         Properties props = readProperties(propertyFile);
 143         toolName = props.getProperty("tool.name");
 144         if (toolName != null) {
 145             toolArgs = props.getProperty(toolName + ".args", "");
 146         }
 147 
 148         if (toolProperty == null ||
 149             askIfUnset && (toolName == null
 150                 || (argsProperty != null && toolArgs == null))) {
 151             showGUI(props);
 152         }
 153 
 154         // finally, return required values, if any
 155         if (toolProperty != null && !(toolName == null || toolName.equals(""))) {
 156             p.setProperty(toolProperty, toolName);
 157 
 158             if (argsProperty != null && toolArgs != null)
 159                 p.setProperty(argsProperty, toolArgs);
 160         }
 161     }
 162 
 163     void showGUI(Properties fileProps) {
 164         Properties guiProps = new Properties(fileProps);
 165         JOptionPane p = createPane(guiProps);
 166         p.createDialog("Select Tool").setVisible(true);
 167 
 168         ToolChoices tool = (ToolChoices)toolChoice.getSelectedItem();
 169 
 170         toolName = tool.toolName;
 171         toolArgs = argsField.getText();
 172         if (defaultCheck.isSelected()) {
 173             if (toolName.equals("")) {
 174                 fileProps.remove("tool.name");
 175                 fileProps.remove("tool.bootstrap");
 176             } else {
 177                 fileProps.remove("tool.bootstrap");
 178                 fileProps.put("tool.name", toolName);
 179                 fileProps.put(toolName + ".args", toolArgs);
 180             }
 181             writeProperties(propertyFile, fileProps);
 182         }
 183     }
 184 
 185     JOptionPane createPane(final Properties props) {
 186         JPanel body = new JPanel(new GridBagLayout());
 187         GridBagConstraints lc = new GridBagConstraints();
 188         lc.insets.right = 10;
 189         lc.insets.bottom = 3;
 190         GridBagConstraints fc = new GridBagConstraints();
 191         fc.gridx = 1;
 192         fc.gridwidth = GridBagConstraints.NONE;
 193         fc.insets.bottom = 3;
 194 
 195         JPanel toolPane = new JPanel(new GridBagLayout());
 196 
 197         JLabel toolLabel = new JLabel("Tool:");
 198         body.add(toolLabel, lc);
 199         EnumSet<ToolChoices> toolChoices = toolProperty == null ?
 200                 EnumSet.allOf(ToolChoices.class) : EnumSet.range(ToolChoices.JAVAC, ToolChoices.JAVAP);
 201         toolChoice = new JComboBox<>(toolChoices.toArray());
 202         ToolChoices tool = toolName != null ? ToolChoices.valueOf(toolName.toUpperCase()) : null;
 203         if (toolName != null) {
 204             toolChoice.setSelectedItem(tool);
 205         }
 206         toolChoice.addItemListener(e -> {
 207             ToolChoices tool1 = (ToolChoices)e.getItem();
 208             argsField.setText(getDefaultArgsForTool(props, tool1));
 209             if (toolProperty != null)
 210                 okButton.setEnabled(tool1 != ToolChoices.NONE);
 211         });
 212         fc.anchor = GridBagConstraints.EAST;
 213 
 214         GridBagConstraints toolConstraint = new GridBagConstraints();
 215         fc.anchor = GridBagConstraints.WEST;
 216 
 217         toolPane.add(toolChoice, toolConstraint);
 218 
 219         body.add(toolPane, fc);
 220 
 221         argsField = new JTextField(getDefaultArgsForTool(props, tool), 40);
 222         if (toolProperty == null || argsProperty != null) {
 223             JLabel argsLabel = new JLabel("Args:");
 224             body.add(argsLabel, lc);
 225             body.add(argsField, fc);
 226             argsField.addFocusListener(new FocusListener() {
 227                 @Override
 228                 public void focusGained(FocusEvent e) {
 229                 }
 230                 @Override
 231                 public void focusLost(FocusEvent e) {
 232                     String toolName = ((ToolChoices)toolChoice.getSelectedItem()).toolName;
 233                     if (toolName.length() > 0)
 234                         props.put(toolName + ".args", argsField.getText());
 235                 }
 236             });
 237         }
 238 
 239         defaultCheck = new JCheckBox("Set as default");
 240         if (toolProperty == null)
 241             defaultCheck.setSelected(true);
 242         else
 243             body.add(defaultCheck, fc);
 244 
 245         final JOptionPane p = new JOptionPane(body);
 246         okButton = new JButton("OK");
 247         okButton.setEnabled(toolProperty == null || (toolName != null && !toolName.equals("")));
 248         okButton.addActionListener(e -> {
 249             JDialog d = (JDialog) SwingUtilities.getAncestorOfClass(JDialog.class, p);
 250             d.setVisible(false);
 251         });
 252         p.setOptions(new Object[] { okButton });
 253 
 254         return p;
 255     }
 256 
 257     Properties readProperties(File file) {
 258         Properties p = new Properties();
 259         if (file != null && file.exists()) {
 260             Reader in = null;
 261             try {
 262                 in = new BufferedReader(new FileReader(file));
 263                 p.load(in);
 264                 in.close();
 265             } catch (IOException e) {
 266                 throw new BuildException("error reading property file", e);
 267             } finally {
 268                 if (in != null) {
 269                     try {
 270                         in.close();
 271                     } catch (IOException e) {
 272                         throw new BuildException("cannot close property file", e);
 273                     }
 274                 }
 275             }
 276         }
 277         return p;
 278     }
 279 
 280     void writeProperties(File file, Properties p) {
 281         if (file != null) {
 282             Writer out = null;
 283             try {
 284                 File dir = file.getParentFile();
 285                 if (dir != null && !dir.exists())
 286                     dir.mkdirs();
 287                 out = new BufferedWriter(new FileWriter(file));
 288                 p.store(out, "langtools properties");
 289                 out.close();
 290             } catch (IOException e) {
 291                 throw new BuildException("error writing property file", e);
 292             } finally {
 293                 if (out != null) {
 294                     try {
 295                         out.close();
 296                     } catch (IOException e) {
 297                         throw new BuildException("cannot close property file", e);
 298                     }
 299                 }
 300             }
 301         }
 302     }
 303 
 304     String getDefaultArgsForTool(Properties props, ToolChoices tool) {
 305         if (tool == null)
 306             return "";
 307         String toolName = tool.toolName;
 308         return toolName.equals("") ? "" : props.getProperty(toolName + ".args", "");
 309     }
 310 
 311     // Ant task parameters
 312     private boolean askIfUnset;
 313     private String toolProperty;
 314     private String argsProperty;
 315     private File propertyFile;
 316 
 317     // GUI components
 318     private JComboBox<?> toolChoice;
 319     private JTextField argsField;
 320     private JCheckBox defaultCheck;
 321     private JButton okButton;
 322 
 323     // Result values for the client
 324     private String toolName;
 325     private String toolArgs;
 326 }