| /******************************************************************************* |
| * Copyright (C) 2013 The University of Manchester |
| * |
| * Modifications to the initial code base are copyright of their |
| * respective authors, or their employers as appropriate. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public License |
| * as published by the Free Software Foundation; either version 2.1 of |
| * the License, or (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
| ******************************************************************************/ |
| package net.sf.taverna.t2.workbench.ui.views.contextualviews.activity; |
| |
| import static java.awt.BorderLayout.CENTER; |
| import static java.awt.BorderLayout.NORTH; |
| import static java.awt.Color.RED; |
| import static java.awt.GridBagConstraints.FIRST_LINE_START; |
| import static java.awt.GridBagConstraints.HORIZONTAL; |
| import static java.awt.event.ItemEvent.DESELECTED; |
| import static java.awt.event.ItemEvent.SELECTED; |
| import static java.util.Arrays.asList; |
| import static javax.swing.Box.createRigidArea; |
| import static javax.swing.BoxLayout.PAGE_AXIS; |
| import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER; |
| import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED; |
| |
| import java.awt.BorderLayout; |
| import java.awt.Dimension; |
| import java.awt.GridBagConstraints; |
| import java.awt.GridBagLayout; |
| import java.awt.Insets; |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ActionListener; |
| import java.awt.event.ItemEvent; |
| import java.awt.event.ItemListener; |
| import java.io.File; |
| import java.io.FilenameFilter; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import javax.swing.BoxLayout; |
| import javax.swing.JCheckBox; |
| import javax.swing.JComboBox; |
| import javax.swing.JLabel; |
| import javax.swing.JPanel; |
| import javax.swing.JScrollPane; |
| import javax.swing.border.EmptyBorder; |
| |
| /** |
| * Component for configuring activities that require dependencies. |
| * |
| * @author David Withers |
| */ |
| @SuppressWarnings("serial") |
| public class DependencyConfigurationPanel extends JPanel { |
| private String classLoaderSharing; |
| private List<String> localDependencies; |
| private File libDir; |
| |
| public DependencyConfigurationPanel(String classLoaderSharing, |
| List<String> localDependencies, File libDir) { |
| this.classLoaderSharing = classLoaderSharing; |
| this.localDependencies = localDependencies; |
| this.libDir = libDir; |
| setLayout(new BoxLayout(this, PAGE_AXIS)); |
| |
| // Create panel with classloading options |
| JPanel classloadingPanel = new ClassloadingPanel(); |
| // Create panel for selecting jar files |
| JPanel jarFilesPanel = new JarFilesPanel(); |
| |
| add(classloadingPanel); |
| add(createRigidArea(new Dimension(0,10))); |
| add(jarFilesPanel); |
| add(createRigidArea(new Dimension(0,10))); |
| |
| } |
| |
| public String getClassLoaderSharing() { |
| return classLoaderSharing; |
| } |
| |
| public List<String> getLocalDependencies() { |
| return localDependencies; |
| } |
| |
| // Classloading option 'workflow' |
| private static final String WORKFLOW = "Shared for whole workflow"; |
| // Classloading option 'system' |
| private static final String SYSTEM = "System classloader"; |
| |
| // Panel containing classloading options |
| private class ClassloadingPanel extends JPanel { |
| // Combobox with classloading options |
| private JComboBox<String> jcbClassloadingOption; |
| // Classloading option descriptions |
| private HashMap<String, String> classloadingDescriptions; |
| // JLabel with classloading option description |
| private JLabel jlClassloadingDescription; |
| |
| /* |
| * Panel containing a list of possible classloading options which users |
| * can select from |
| */ |
| private ClassloadingPanel() { |
| super(new GridBagLayout()); |
| jcbClassloadingOption = new JComboBox<>(new String[] { WORKFLOW, |
| SYSTEM }); |
| // Set the current classlaoding option based on the configuration bean |
| if ("workflow".equals(classLoaderSharing)) { |
| jcbClassloadingOption.setSelectedItem(WORKFLOW); |
| } else if ("system".equals(classLoaderSharing)) { |
| jcbClassloadingOption.setSelectedItem(SYSTEM); |
| } |
| |
| jcbClassloadingOption.addActionListener(new ActionListener(){ |
| // Fires up when combobox selection changes |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| Object selectedItem = jcbClassloadingOption.getSelectedItem(); |
| jlClassloadingDescription.setText(classloadingDescriptions |
| .get(selectedItem)); |
| if (selectedItem.equals(WORKFLOW)) |
| classLoaderSharing = "workflow"; |
| else if (selectedItem.equals(SYSTEM)) |
| classLoaderSharing = "system"; |
| } |
| }); |
| //jcbClassloadingOption.setEnabled(false); |
| |
| classloadingDescriptions = new HashMap<>(); |
| classloadingDescriptions.put(WORKFLOW, "<html><small>" |
| + "Classes are shared across the whole workflow (with any service<br>" |
| + "also selecting this option), but are reinitialised for each workflow run.<br>" |
| + "This might be needed if a service passes objects to another, or <br>" |
| + "state is shared within static members of loaded classes." |
| + "</small></html>"); |
| classloadingDescriptions.put(SYSTEM, "<html><small><p>" |
| + "The (global) system classloader is used, any dependencies defined here are<br>" |
| + "made available globally on the first run. Note that if you are NOT using<br>" |
| + "the defaulf Taverna BootstrapClassLoader, any settings here will be disregarded." |
| + "</p><p>" |
| + "This is mainly useful if you are using JNI-based libraries. Note that <br>" |
| + "for JNI you also have to specify <code>-Djava.library.path</code> and <br>" |
| + "probably your operating system's dynamic library search path<br>" |
| + "<code>LD_LIBRARY_PATH</code> / <code>DYLD_LIBRARY_PATH</code> / <code>PATH</code> </p>" |
| + "</small></html>"); |
| |
| /* |
| * Set the current classlaoding description based on the item |
| * selected in the combobox. |
| */ |
| jlClassloadingDescription = new JLabel(classloadingDescriptions |
| .get(jcbClassloadingOption.getSelectedItem())); |
| |
| // Add components to the ClassloadingPanel |
| GridBagConstraints c = new GridBagConstraints(); |
| c.anchor = FIRST_LINE_START; |
| c.fill = HORIZONTAL; |
| c.gridx = 0; |
| c.insets = new Insets(10,0,0,0); |
| add(new JLabel("Classloader persistence"), c); |
| c.insets = new Insets(0,0,0,0); |
| add(jcbClassloadingOption, c); |
| c.insets = new Insets(0,30,0,0); |
| add(jlClassloadingDescription, c); |
| } |
| } |
| |
| // Panel for users to add local JAR dependencies (contains a list of jar files which users can select from) |
| private class JarFilesPanel extends JPanel { |
| private JLabel warning = new JLabel( |
| "<html>" |
| + "<center<font color='red'>" |
| + "Warning: Depending on local libraries makes this workflow<br>" |
| + "difficult or impossible to run for other users. Try depending<br>" |
| + "on artifacts from a public repository if possible.</font></center>" |
| + "</html>"); |
| |
| private JarFilesPanel() { |
| super(); |
| setMinimumSize(new Dimension(400, 150)); |
| setLayout(new BorderLayout()); |
| setBorder(new EmptyBorder(0,10,0,10)); |
| |
| JPanel labelPanel = new JPanel(); |
| labelPanel.setLayout(new BoxLayout(labelPanel, PAGE_AXIS)); |
| JLabel label = new JLabel("Local JAR files"); |
| JLabel libLabel = new JLabel("<html><small>" + libDir.getAbsolutePath() |
| + "</small></html>"); |
| labelPanel.add(label); |
| labelPanel.add(libLabel); |
| |
| add(labelPanel, NORTH); |
| add(new JScrollPane(jarFiles(), VERTICAL_SCROLLBAR_AS_NEEDED, |
| HORIZONTAL_SCROLLBAR_NEVER), CENTER); |
| |
| warning.setVisible(false); |
| /* |
| * We'll skip the warning until we actually have support for |
| * artifacts |
| */ |
| //add(warning); |
| updateWarning(); |
| } |
| |
| private void updateWarning() { |
| // Show warning if there is any local dependencies |
| warning.setVisible(!localDependencies.isEmpty()); |
| } |
| |
| public JPanel jarFiles() { |
| JPanel panel = new JPanel(); |
| panel.setLayout(new BoxLayout(panel, PAGE_AXIS)); |
| |
| // List of all jar files in the lib directory |
| List<String> jarFiles = asList(libDir |
| .list(new FileExtFilter(".jar"))); |
| /* |
| * We also add the list of jars that may have been configured |
| * sometime before but are now not present in the lib directory for |
| * some reason |
| */ |
| Set<String> missingLocalDeps = new HashSet<>(localDependencies); |
| missingLocalDeps.removeAll(jarFiles); |
| /* |
| * jarFiles and missingLocalDeps now contain two sets of files that |
| * do not intersect |
| */ |
| List<String> jarFilesList = new ArrayList<>(); |
| // Put them all together |
| jarFilesList.addAll(jarFiles); |
| jarFilesList.addAll(missingLocalDeps); |
| Collections.sort(jarFilesList); |
| |
| if (jarFilesList.isEmpty()) { |
| panel.add(new JLabel("<html><small>To depend on a JAR file, " |
| + "copy it to the above-mentioned folder.</small></html>")); |
| return panel; |
| } |
| |
| for (String jarFile : jarFilesList) { |
| JCheckBox checkBox = new JCheckBox(jarFile); |
| // Has it already been selected in some previous configuring? |
| checkBox.setSelected(localDependencies.contains(jarFile)); |
| checkBox.addItemListener(new ItemListener() { |
| @Override |
| public void itemStateChanged(ItemEvent e) { |
| JCheckBox box = (JCheckBox) e.getSource(); |
| if (e.getStateChange() == SELECTED) |
| localDependencies.add(box.getText()); |
| else if (e.getStateChange() == DESELECTED) |
| localDependencies.remove(box.getText()); |
| updateWarning(); |
| } |
| }); |
| panel.add(checkBox); |
| // The jar may not be in the lib directory, so warn the user |
| if (!new File(libDir, jarFile).exists()) { |
| checkBox.setForeground(RED); |
| checkBox.setText(checkBox.getText() + " (missing file!)"); |
| } |
| } |
| return panel; |
| } |
| } |
| |
| public static class FileExtFilter implements FilenameFilter { |
| final String ext; |
| |
| public FileExtFilter(String ext) { |
| this.ext = ext; |
| } |
| |
| @Override |
| public boolean accept(File dir, String name) { |
| return name.endsWith(ext); |
| } |
| } |
| } |