source: main/trunk/gli/src/org/greenstone/gatherer/gui/DownloadPane.java@ 31821

Last change on this file since 31821 was 31821, checked in by ak19, 7 years ago

Removing the (commented) out debug statements introduced during the previous commit.

  • Property svn:keywords set to Author Date Id Revision
File size: 29.6 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.gui;
38
39import java.awt.*;
40import java.awt.event.*;
41import java.io.*;
42import java.net.*;
43import java.util.*;
44import javax.swing.*;
45import javax.swing.border.*;
46import javax.swing.event.*;
47import javax.swing.tree.*;
48import org.greenstone.gatherer.Configuration;
49import org.greenstone.gatherer.DebugStream;
50import org.greenstone.gatherer.Dictionary;
51import org.greenstone.gatherer.Gatherer;
52import org.greenstone.gatherer.file.WorkspaceTree;
53import org.greenstone.gatherer.greenstone.LocalGreenstone;
54import org.greenstone.gatherer.util.SafeProcess;
55import org.greenstone.gatherer.util.StaticStrings;
56import org.greenstone.gatherer.util.Utility;
57import org.greenstone.gatherer.download.Download;
58import org.greenstone.gatherer.download.DownloadScrollPane;
59import org.greenstone.gatherer.download.ServerInfoDialog;
60import org.greenstone.gatherer.util.XMLTools;
61import org.greenstone.gatherer.cdm.*;
62import org.greenstone.gatherer.gui.*;
63import org.w3c.dom.*;
64import org.xml.sax.*;
65import org.greenstone.gatherer.GAuthenticator;
66
67/**
68 * @author John Thompson, Greenstone Digital Library, University of Waikato
69 * @version 2.1
70 */
71public class DownloadPane
72 extends JPanel {
73
74 static final private Dimension LABEL_SIZE = new Dimension(225, 25);
75 static final private Dimension TREE_SIZE = new Dimension(150, 500);
76 //static final private String CONTENTS[] = { "DOWNLOAD.MODE.WebDownload", "DOWNLOAD.MODE.MediaWikiDownload", "DOWNLOAD.MODE.OAIDownload", "DOWNLOAD.MODE.ZDownload" , "DOWNLOAD.MODE.SRWDownload"};
77 private String CONTENTS[] = null;
78
79 private boolean download_button_enabled = false;
80 private boolean ready = false;
81
82 private JPanel options_pane;
83 // TODO should use Vector to store all loaded downloads!!
84
85 private DesignTree tree;
86 private HashMap download_map;
87 private ServerInfoDialog server_info;
88 private JScrollPane list_scroll;
89 private DownloadScrollPane getter;
90 private String mode = null;
91 private TreePath previous_path;
92 private String proxy_url = "";
93 private Proxy proxyObject = null;
94
95 /** Main System code */
96 public DownloadPane() {
97 super();
98 JScrollPane scrol_tmp;
99 this.setComponentOrientation(Dictionary.getOrientation());
100 // TODO: Download the WDownload and the download panel fixed!!
101 getter = new DownloadScrollPane();
102 getter.start();
103 list_scroll = getter.getDownloadJobList();
104 list_scroll.setComponentOrientation(Dictionary.getOrientation());
105
106 // TODO should use Vector to store all loaded downloads!!
107 String lang = Configuration.getLanguage();
108 download_map = new HashMap();
109
110 // run downloadinfo.pl -describeall, load the downloaders into the download_map,
111 // and get back their list of names, which are of the form "<downloader>Download".
112 // Store these names in the CONTENTS[] array as "DOWNLOAD.MODE.<downloader>Download",
113 // with z3950 as a minor exception: DOWNLOAD.MODE.ZDownload.
114 ArrayList<String> downloaderNamesList = loadDownloadersInfo(lang);
115 int size = downloaderNamesList.size();
116 CONTENTS = new String[size];
117 for(int i = 0; i < size; i++) {
118 String downloadName = downloaderNamesList.get(i); // e.g. "WebDownload"
119 CONTENTS[i] = "DOWNLOAD.MODE."+downloadName.replace("3950", ""); // A special case is Z3950Download,
120 // which has to be stored in CONTENTS array as DOWNLOAD.MODE.ZDownload
121 }
122
123 // Creation
124 tree = new DesignTree();
125 tree.setComponentOrientation(Dictionary.getOrientation());
126 options_pane = new JPanel();
127 options_pane.setComponentOrientation(Dictionary.getOrientation());
128
129 JButton clear_cache_button = new GLIButton(Dictionary.get("Mirroring.ClearCache"), Dictionary.get("Mirroring.ClearCache_Tooltip"));
130 clear_cache_button.setEnabled(true);
131 clear_cache_button.setMnemonic(KeyEvent.VK_C);
132
133 JButton download_button = new GLIButton(Dictionary.get("Mirroring.Download"), Dictionary.get("Mirroring.Download_Tooltip"));
134 download_button.setEnabled(true);
135 download_button.setMnemonic(KeyEvent.VK_D);
136
137 JButton information_button = new GLIButton(Dictionary.get("Download.ServerInformation"), Dictionary.get("Download.ServerInformation_Tooltip"));
138 information_button.setEnabled(true);
139 information_button.setMnemonic(KeyEvent.VK_S);
140
141
142 JButton preferences_button = new GLIButton(Dictionary.get("Mirroring.Preferences"), Dictionary.get("Mirroring.Preferences_Tooltip"));
143 preferences_button.setEnabled(true);
144 preferences_button.setMnemonic(KeyEvent.VK_P);
145
146 // Connect
147 clear_cache_button.addActionListener(new ClearCacheListener());
148 download_button.addActionListener(new DownloadButtonListener());
149 preferences_button.addActionListener(new PreferencesButtonActionListener());
150 information_button.addActionListener(new InformationButtonActionListener());
151 tree.addTreeSelectionListener(new TreeListener());
152
153 // Add to Panel
154 JPanel button_pane = new JPanel();
155 button_pane.setComponentOrientation(Dictionary.getOrientation());
156 button_pane.setLayout(new GridLayout(1,4)); // GridLayout so button pane resizes with window-width
157 button_pane.setBorder(BorderFactory.createEtchedBorder());
158 button_pane.add(clear_cache_button);
159 button_pane.add(download_button);
160 button_pane.add(information_button);
161 button_pane.add(preferences_button);
162
163 JPanel tree_pane = new JPanel();
164 tree_pane.setComponentOrientation(Dictionary.getOrientation());
165 tree_pane.setLayout(new BorderLayout());
166 scrol_tmp = new JScrollPane(tree);
167 scrol_tmp.setComponentOrientation(Dictionary.getOrientation());
168 tree_pane.add(scrol_tmp, BorderLayout.CENTER);
169 tree_pane.setPreferredSize(TREE_SIZE);
170
171
172 Color colour_two = Configuration.getColor("coloring.collection_tree_background", false);
173 options_pane.setBackground(colour_two);
174 options_pane.setBorder(BorderFactory.createEtchedBorder());
175
176
177 JScrollPane options_scroll_pane = new JScrollPane(options_pane);
178 options_scroll_pane.setComponentOrientation(Dictionary.getOrientation());
179 JSplitPane mode_pane = new JSplitPane();
180 mode_pane.setComponentOrientation(Dictionary.getOrientation());
181 mode_pane.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
182 if (Dictionary.getOrientation().isLeftToRight()){
183 mode_pane.add(tree_pane,JSplitPane.LEFT);
184 mode_pane.add(options_scroll_pane,JSplitPane.RIGHT);
185 mode_pane.setDividerLocation(TREE_SIZE.width);
186 }else{
187 mode_pane.add(tree_pane,JSplitPane.RIGHT);
188 mode_pane.add(options_scroll_pane,JSplitPane.LEFT);
189 mode_pane.setDividerLocation(1-TREE_SIZE.width);
190 }
191
192
193 JPanel edit_pane = new JPanel();
194 edit_pane.setComponentOrientation(Dictionary.getOrientation());
195 edit_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(2,0,0,0), BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder("Download Setting"), BorderFactory.createEmptyBorder(2,2,2,2))));
196 edit_pane.setLayout(new BorderLayout());
197 edit_pane.add(mode_pane,BorderLayout.CENTER);
198 edit_pane.add(button_pane,BorderLayout.PAGE_END);
199
200 // Add to "this"
201 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
202 setLayout(new GridLayout(2,1));
203 add(edit_pane);
204 add(list_scroll);
205
206 //set the mode to the first downloader in the list
207 mode = convertCONTENTStoMode(CONTENTS[0]); // e.g. Web
208 generateOptions(options_pane,(Download)download_map.get(mode));
209 previous_path = tree.getSelectionPath();
210 }
211
212 /** System Utilities */
213 public void modeChanged(int gli_mode) {
214 // do nothing at this stage - should we be renewing download options??
215 }
216
217 private void addHeader(String name, Color color, JPanel target_pane) {
218 JPanel header = new JPanel();
219 header.setComponentOrientation(Dictionary.getOrientation());
220 header.setBackground(color);
221 JPanel inner_pane = new JPanel();
222 inner_pane.setComponentOrientation(Dictionary.getOrientation());
223 inner_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createRaisedBevelBorder()));
224 inner_pane.setBackground(color);
225 JLabel header_label = new JLabel("<html><strong>" + name + "</strong></html>");
226 header_label.setComponentOrientation(Dictionary.getOrientation());
227 header_label.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
228 header_label.setHorizontalAlignment(JLabel.CENTER);
229 header_label.setOpaque(true);
230
231 // Layout
232 inner_pane.setLayout(new BorderLayout());
233 inner_pane.add(header_label, BorderLayout.CENTER);
234
235 header.setLayout(new BorderLayout());
236 header.add(inner_pane, BorderLayout.CENTER);
237 target_pane.add(header);
238 }
239
240 /** Supporting Functions */
241 private ArrayList<String> loadDownloadersInfo(String lang) {
242 Document document = null;
243
244 try {
245 if (Gatherer.isGsdlRemote) {
246 String output = Gatherer.remoteGreenstoneServer.getScriptOptions("downloadinfo.pl", "&describeall");
247 Reader reader = new StringReader(output);
248 document = XMLTools.parseXML(reader);
249 }
250 else {
251 ArrayList args_list = new ArrayList();
252 String args[] = null;
253 if(Configuration.perl_path != null) {
254 args_list.add(Configuration.perl_path);
255 } else if(Utility.isWindows()) {
256 args_list.add("Perl.exe");
257 } else {
258 args_list.add("perl");
259 }
260 args_list.add("-S");
261 args_list.add(LocalGreenstone.getBinScriptDirectoryPath()+"downloadinfo.pl");
262 args_list.add("-describeall");
263 args_list.add("-xml");
264 args_list.add("-language");
265 args_list.add(lang);
266
267 // Create the process.
268 args = (String []) args_list.toArray(new String[0]);
269
270 SafeProcess process = new SafeProcess(args);
271 DebugStream.println("Getting Download Info: "+args_list);
272
273 // run the SafeProcess
274 int exitVal = process.runProcess();
275 if(exitVal != 0) {
276 throw new Exception("*** Error running Download Info process, process exited with: "
277 + exitVal);
278 }
279
280 // get the result and process it.
281 // This time we expect XML to have come out of the process std error stream.
282 String errStreamOutput = process.getStdError();
283 ///System.err.println("*********\nDownload Pane data, got:\n" + errStreamOutput + "\n**********\n");
284 StringReader xmlStrReader = new StringReader(errStreamOutput);
285 document = XMLTools.parseXML(xmlStrReader);
286 xmlStrReader.close();
287
288 }
289
290
291 }
292 catch (Exception error) {
293 System.err.println("Failed when trying to parse downloadinfo.pl -describeall");
294 error.printStackTrace();
295 }
296
297 if(document != null) {
298 return parseXML(document.getDocumentElement());
299 }
300
301 return null;
302 }
303
304 private ArrayList<String> parseXML(Node root) {
305 ArrayList<String> downloaders = null;
306 Element downloadList = (Element)root;
307 int length = -1;
308 if(downloadList.hasAttribute("length")) {
309 length = Integer.parseInt(downloadList.getAttribute("length"));
310 downloaders = new ArrayList<String>(length);
311
312 for (Node node = downloadList.getFirstChild(); node != null; node = node.getNextSibling()) {
313 // goes through each <DownloadInfo> of describeAll
314
315 String download_name = null;
316
317 for(Node infoNode = node.getFirstChild();
318 infoNode != null; infoNode = infoNode.getNextSibling()) {
319
320 String node_name = infoNode.getNodeName();
321 if(node_name.equalsIgnoreCase("Name")) { // <Name>WebDownload</Name>
322 download_name = XMLTools.getValue(infoNode); // e.g. WebDownload
323 }
324
325 // At this top level of <DownloadInfo> elements,
326 // skip all the downloaders that are Abstract, as these are pure superclasses
327 else if(node_name.equalsIgnoreCase("Abstract")) {
328 String isAbstract = XMLTools.getValue(infoNode);
329
330 if(isAbstract.equalsIgnoreCase("no") && download_name != null) {
331 downloaders.add(download_name);
332 Download downloader = parseDownloadInfoXML(node); // parse the <DownloadInfo> node properly
333 // now embedded references to abstract superclasses (embedded <DownloadInfo> nodes)
334 // will be handled
335
336 String shortName = download_name.replace("Download", ""); // e.g. "Web"
337 download_map.put(shortName, downloader);
338 }
339 }
340 }
341 }
342 }
343
344 return downloaders;
345 }
346
347 private Download parseDownloadInfoXML(Node root) {
348
349 Download download = new Download();
350 String node_name = null;
351 for (Node node = root.getFirstChild(); node != null; node = node.getNextSibling()) {
352 node_name = node.getNodeName();
353 if(node_name.equalsIgnoreCase("Name")) {
354 String name = XMLTools.getValue(node);
355 download.setName(name);
356 }
357 else if (node_name.equalsIgnoreCase("Desc")) {
358 download.setDescription(XMLTools.getValue(node));
359 }
360 else if (node_name.equalsIgnoreCase("Abstract")) {
361 download.setIsAbstract(XMLTools.getValue(node).equalsIgnoreCase(StaticStrings.YES_STR));
362 }
363 else if(node_name.equalsIgnoreCase("Arguments")) {
364 for(Node arg = node.getFirstChild(); arg != null; arg = arg.getNextSibling()) {
365 node_name = arg.getNodeName();
366 if(node_name.equalsIgnoreCase("Option")) {
367 Argument argument = new Argument((Element)arg);
368 argument.parseXML((Element)arg);
369 argument.setValue(argument.getDefaultValue());
370 download.addArgument(argument);
371 }
372
373 }
374 }
375 else if(node_name.equalsIgnoreCase("DownloadInfo")) {
376 Download super_download = parseDownloadInfoXML(node);
377 download.setSuper(super_download);
378 }
379 }
380
381 if(download.getName() != null) {
382 return download;
383 }
384 return null;
385 }
386
387 /** Update the previous setup */
388 private boolean updateArguments(boolean checkRequired)
389 {
390 boolean cont = true;
391 for(int i = 0; i < options_pane.getComponentCount(); i++) {
392
393 Component component = options_pane.getComponent(i);
394 if(component instanceof ArgumentControl) {
395 cont = cont && ((ArgumentControl)component).updateArgument(checkRequired);
396 }
397 }
398
399 if(cont){return true; }
400
401 return false;
402 }
403
404 /** Generate Controls for Options */
405 /* at some stage we should think about which options should be shown for
406 * different modes. Currently, always show all options (unless hidden)*/
407 private void generateOptions(JPanel options_pane, ArgumentContainer data) {
408 options_pane.removeAll();
409 /** Create the current option panel */
410
411 ArrayList arguments = data.getArguments(true, false);
412 int mode = Configuration.getMode();
413 ArrayList added_arguments = new ArrayList();
414
415 for(int i = 0; i < arguments.size(); i++) {
416 Argument argument = (Argument) arguments.get(i);
417
418 if (argument.isHiddenGLI()) continue;
419 ArgumentControl argument_control = new ArgumentControl(argument,false,null);
420 added_arguments.add(argument_control);
421 }
422
423
424 options_pane.setLayout(new GridLayout(added_arguments.size(),1));
425 for(int i = 0; i < added_arguments.size(); i++) {
426 options_pane.add((ArgumentControl)added_arguments.get(i));
427
428 }
429 }
430
431 /** Behaviour Functions */
432 public void afterDisplay() {
433 ready = true;
434 }
435
436
437 public void gainFocus() {
438 if(!ready) {
439 return;
440 }
441
442 // It is also a good time to determine if the download should be enabled - ie if its allowed to be enabled and a valid URL is present in the field.
443 download_button_enabled = true;
444 //download_button.setEnabled(download_button_enabled);
445 }
446
447
448
449 public void refresh(int refresh_reason, boolean ready)
450 {
451 }
452
453 /** Private classes */
454 /** This tree provides a 'table of contents' for the various components of the design process (collection configuration in more technical terms). */
455 private class DesignTree extends JTree {
456
457 private DesignNode root = null;
458 /** Constructor. Automatically generates all of the nodes, in the order of CONTENTS. */
459 public DesignTree() {
460 super();
461 this.setComponentOrientation(Dictionary.getOrientation());
462 resetModel(Configuration.getMode());
463 expandRow(0);
464 setRootVisible(false);
465 setSelectionRow(0);
466 }
467
468 /** Reset the model used by the design page contents tree. This is necessary to hide the partitions entry when in lower detail modes
469 * @param mode the current detail mode as an int
470 */
471 public void resetModel(int mode) {
472 root = new DesignNode("DOWNLOAD.MODE.Root");
473 // Now add the design categories.
474 for(int i = 0; i < CONTENTS.length; i++) {
475 root.add(new DesignNode(CONTENTS[i]));
476 }
477 this.setModel(new DefaultTreeModel(root));
478 updateUI();
479 }
480 /** Set the current view to the one specified.
481 * @param type the name of the desired view as a String
482 */
483 public void setSelectedView(String type) {
484 type = Dictionary.get(type);
485 for(int i = 0; i < root.getChildCount(); i++) {
486 DesignNode child = (DesignNode) root.getChildAt(i);
487 if(child.toString().equals(type)) {
488 TreePath path = new TreePath(child.getPath());
489 setSelectionPath(path);
490 }
491 }
492 }
493 }
494
495 /** A tree node that retains a reference to one of the possible design sub-views relating to the different sub-managers. */
496 private class DesignNode extends DefaultMutableTreeNode {
497 /** Constructor.
498 * @param object The <strong>Object</strong> assigned to this node.
499 */
500 public DesignNode(String object) {
501 super(object);
502 }
503 /** Retrieve a textual representation of the object.
504 * @return a String
505 */
506 public String toString() {
507 // return Dictionary.get("CDM.GUI." + (String)getUserObject());
508 return Dictionary.get((String) getUserObject());
509 }
510 }
511
512 /** Listens for selection changes in the 'contents' tree, and switches to the appropriate view. */
513 private class TreeListener
514 implements TreeSelectionListener {
515 /** Called whenever the selection changes, we must update the view so it matches the node selected.
516 * @param event A <strong>TreeSelectionEvent</strong> containing more information about the tree selection.
517 * @see org.greenstone.gatherer.cdm.ClassifierManager
518 * @see org.greenstone.gatherer.cdm.CollectionDesignManager
519 * @see org.greenstone.gatherer.cdm.CollectionMetaManager
520 * @see org.greenstone.gatherer.cdm.FormatManager
521 * @see org.greenstone.gatherer.cdm.LanguageManager
522 * @see org.greenstone.gatherer.cdm.MetadataSetView
523 * @see org.greenstone.gatherer.cdm.SubcollectionManager
524 * @see org.greenstone.gatherer.cdm.TranslationView
525 * @see org.greenstone.gatherer.cdm.PlugInManager
526 */
527 public void valueChanged(TreeSelectionEvent event) {
528 if(!tree.isSelectionEmpty()) {
529 TreePath path = tree.getSelectionPath();
530
531 DesignNode node = (DesignNode)path.getLastPathComponent();
532 String type = (String)node.getUserObject();
533 Gatherer.g_man.wait(true);
534
535 // type has the value DOWNLOAD.MODE.<downloader>Download,
536 // mode should then be of the form <downloader>
537 mode = convertCONTENTStoMode(type);
538 generateOptions(options_pane,(Download)download_map.get(mode));
539
540 tree.setSelectionPath(path);
541 previous_path = path;
542 repaint();
543
544 Gatherer.g_man.wait(false);
545 }
546 }
547 }
548
549 private String convertCONTENTStoMode(String content) {
550 return content.replace("DOWNLOAD.MODE.", "").replace("ZDownload", "Z3950").replace("Download", "");
551 }
552
553 private class ClearCacheListener
554 implements ActionListener {
555 public void actionPerformed(ActionEvent event) {
556 // Retrieve the cache folder and delete it.
557 Utility.delete(Utility.getCacheDir());
558 // ...and refresh the node in the workspace tree to show it's all gone
559 Gatherer.g_man.refreshWorkspaceTree(WorkspaceTree.DOWNLOADED_FILES_CHANGED);
560 }
561 }
562
563 private class DownloadButtonListener
564 implements ActionListener {
565 public void actionPerformed(ActionEvent event) {
566
567 if(checkURL(true) && checkProxy() == true) {
568
569 // Proxy settings are now set. Check that the url is not a redirect, else get
570 // redirect url (we do this step in order to avoid some unintuitive behaviour from wget)
571 Download current_download = (Download)download_map.get(mode);
572 Argument arg_url = current_download.getArgument("url");
573 if(arg_url != null) { // it's null for z3950 and possibly for other downloaders
574 String url_str = arg_url.getValue();
575 String redirect_url_str = getRedirectURL(url_str);
576
577 // only update the Argument and its GUI ArgumentControl if the URL
578 // has in fact changed
579 if(!url_str.equals(redirect_url_str)) {
580 arg_url.setValue(redirect_url_str);
581 updateArgument(arg_url, redirect_url_str);
582 }
583 }
584 getter.newDownloadJob((Download)download_map.get(mode) ,mode,proxy_url);
585 }
586 }
587 }
588
589 /**
590 * The Java code here will retrieve the page at the given url. If the response code is
591 * a redirect, it will get the redirect url so that wget may be called with the proper url.
592 * This preprocessing of the URL is necessary because:
593 * Wget does not behave the way the browser does when faced with urls of the form
594 * http://www.englishhistory.net/tudor/citizens and if that page does not exist.
595 * The directory listing with a slash at the end (http://www.englishhistory.net/tudor/citizens/)
596 * does exist, however. In order to prevent wget from assuming that the root URL
597 * to traverse is http://www.englishhistory.net/tudor/ instead of the intended
598 * http://www.englishhistory.net/tudor/citizens/, we need give wget the redirect location
599 * that's returned when we initially make a request for http://www.englishhistory.net/tudor/citizens
600 * The proper url is sent back in the Location header, allowing us to bypass wget's
601 * unexpected behaviour.
602 * This method ensures that urls like http://www.nzdl.org/niupepa also continue to work:
603 * there is no http://www.nzdl.org/niupepa/ page, because this url actually redirects to an
604 * entirely different URL.
605 * @return the redirect url for the given url if any redirection is involved, or the
606 * url_str.
607 *
608 * Adding another useful URL on setting Java System Properties:
609 * https://stackoverflow.com/questions/12181843/using-java-to-download-files-from-a-https-url
610 */
611 private String getRedirectURL(String url_str) {
612 boolean noMoreRedirects = false;
613
614 HttpURLConnection connection = null;
615 if(url_str.startsWith("http:") || url_str.startsWith("https:")) { // only test http urls
616 try {
617 URL url = new URL(url_str);
618 if(this.proxyObject == null) {
619 connection = (HttpURLConnection)url.openConnection(); //new HttpURLConnection(url);
620 } else {
621 connection = (HttpURLConnection)url.openConnection(proxyObject);
622 }
623 // don't let it automatically follow redirects, since we want to
624 // find out whether we are dealing with redirects in the first place
625 connection.setInstanceFollowRedirects(false);
626 connection.setConnectTimeout(5 * 1000); // ms
627
628 // now check for whether we get a redirect response
629 // HTTP Codes 3xx are redirects, http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
630 int responseCode = connection.getResponseCode();
631 if(responseCode >= 300 && responseCode < 400) {
632 //String responseMsg = connection.getResponseMessage();
633
634 // Get the Location header since this specifies the new location of the resource
635 String location = connection.getHeaderField("Location");
636
637 // this becomes the url that wget should download from
638 url_str = location.trim();
639 } else {
640 noMoreRedirects = true;
641 }
642 connection.disconnect();
643 } catch(Exception e) {
644 if(connection != null) {
645 connection.disconnect();
646 }
647 System.err.println("Checking redirection. Tried to connect to "
648 + url_str + ",\nbut got exception: " + e);
649 }
650 }
651
652 if(noMoreRedirects) {
653 return url_str;
654 }
655 else { // continue checking for whether the new URL redirects elsewhere again
656 return getRedirectURL(url_str);
657 }
658 }
659
660
661 /** For a string-based Argument whose value has changed, this method
662 * updates the GUI ArgumentControl's value correspondingly. */
663 private void updateArgument(Argument arg, String value) {
664 for(int i = 0; i < options_pane.getComponentCount(); i++) {
665 Component component = options_pane.getComponent(i);
666 if(component instanceof ArgumentControl) {
667 ArgumentControl control = (ArgumentControl)component;
668 if(control.getArgument() == arg) {
669 control.setValue(value);
670 control.repaint();
671 }
672 }
673 }
674 }
675
676 private boolean checkURL(boolean checkRequired){
677
678 if (!updateArguments(checkRequired)){
679 return false;
680 }
681
682 Download current_download = (Download)download_map.get(mode);
683 Argument arg_url = current_download.getArgument("url");
684
685 if (arg_url == null) return true;
686
687 String url_str = arg_url.getValue();
688 URL url = null;
689 try {
690 url = new URL(url_str);
691 }
692 catch(MalformedURLException error) {
693 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("Mirroring.Invalid_URL"), Dictionary.get("Mirroring.Invalid_URL_Title"), JOptionPane.ERROR_MESSAGE);
694 return false;
695 }
696
697 return true;
698 }
699
700
701 private boolean checkProxy(){
702
703 proxy_url = null;
704
705 Download current_download = (Download)download_map.get(mode);
706
707 Argument arg = current_download.getArgument("proxy_on");
708
709 if (arg == null) return true;
710
711 // Determine if we have to use a proxy.
712 if(Configuration.get("general.use_proxy", true)) {
713
714 String proxy_host = Configuration.getString("general.proxy_host", true);
715 String proxy_port = Configuration.getString("general.proxy_port", true);
716 // Find out whether the user has already authenticated themselves
717 String user_pass = "";
718 String address = proxy_host + ":" + proxy_port;
719
720 int count = 0;
721 // Only for wget, need to avoid a second automatic authentication popup (first asks
722 // the proxy authentication for wget, and the second will ask the same for the realm)
723 // Once the authentication has been reused, it will set the GAuthenticator state back to REGULAR
724 GAuthenticator.setMode(GAuthenticator.DOWNLOAD);
725 while(count < 3 && (user_pass = (String) GAuthenticator.authentications.get(address)) == null) {
726 Authenticator.requestPasswordAuthentication(proxy_host, null, Integer.parseInt(proxy_port), "http://", Dictionary.get("WGet.Prompt"), "HTTP");
727 count++;
728 }
729 if(count >= 3) {
730 return false;
731 }
732
733 // https://askubuntu.com/questions/664777/systemwide-proxy-settings-in-ubuntu
734 // http://www.rgagnon.com/javadetails/java-0085.html
735 // how-do-i-make-httpurlconnection-use-a-proxy
736 // https://stackoverflow.com/questions/8030908/how-to-check-if-proxy-is-working-in-java
737 proxyObject = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxy_host, Integer.parseInt(proxy_port)));
738
739 if(user_pass.indexOf("@") != -1) {
740
741 // Write the use proxy command - we don't do this anymore, instead we set environment variables - hopefully these can't be spied on like the following can (using ps) - actually the environment stuff didn't work for windows, so lets go back to this
742 if (Utility.isWindows()) {
743
744 arg.setValue("true");
745 arg.setAssigned(true);
746
747 arg = current_download.getArgument("proxy_host");
748 arg.setValue(proxy_host);
749 arg.setAssigned(true);
750
751 arg = current_download.getArgument("proxy_port");
752 arg.setValue(proxy_port);
753 arg.setAssigned(true);
754
755 arg = current_download.getArgument("user_name");
756 arg.setValue(user_pass.substring(0, user_pass.indexOf("@")));
757 arg.setAssigned(true);
758
759 arg = current_download.getArgument("user_password");
760 arg.setValue(user_pass.substring(user_pass.indexOf("@") + 1));
761 arg.setAssigned(true);
762 }
763 else{
764 String user_name = user_pass.substring(0, user_pass.indexOf("@"));
765 String user_pwd = user_pass.substring(user_pass.indexOf("@") + 1);
766 proxy_url = user_name+":"+user_pwd+"@"+proxy_host+":"+proxy_port+"/";
767
768 }
769
770 return true;
771 }
772 else{
773 return false;
774 }
775
776 }
777
778 return true;
779 }
780
781 /*
782 private class PreferencesButtonActionListener
783 implements ActionListener {
784 public void actionPerformed(ActionEvent event) {
785 new Preferences(Preferences.CONNECTION_PREFS);
786 }
787 }*/
788
789 private class InformationButtonActionListener
790 implements ActionListener {
791 public void actionPerformed(ActionEvent event) {
792 //turn off the check for find argument
793 Download current_download = (Download)download_map.get(mode);
794
795 if (!checkProxy() || !checkURL(false) )return;
796
797 if(server_info != null) {
798 server_info.dispose();
799 }
800
801 Argument arg_url = current_download.getArgument("url");
802 String str_url = "";
803 if( arg_url!= null && arg_url.isAssigned()) {
804 str_url = arg_url.getValue();
805 }
806
807 str_url = getRedirectURL(str_url); // work out the real URL
808
809 server_info = new ServerInfoDialog(str_url ,proxy_url, mode,(Download)download_map.get(mode));
810
811 }
812 }
813
814 private class PreferencesButtonActionListener
815 implements ActionListener {
816 public void actionPerformed(ActionEvent event) {
817 new Preferences(Preferences.CONNECTION_PREFS);
818 }
819 }
820}
Note: See TracBrowser for help on using the repository browser.