Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/lanceolav/jreftree/WebTools.java


1   /**
2    * JRefTree is a GUI interface to organize and output bibliographic references.
3    * Copyright (C) 2003 Lance O. Eastgate.
4    *
5    * This file is part of JRefTree, and was created on Apr 1, 2003.
6    *
7    * JRefTree is free software; you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation; either version 2
10   * of the License, or (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with this program; if not, write to the Free Software
19   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20   *
21   * The author can be reached at jreftree@lanceolav.com.
22   */
23  
24  package com.lanceolav.jreftree;
25  
26  import com.lanceolav.jreftree.dialogs.PleaseWaitWindow;
27  import org.w3c.dom.*;
28  import org.xml.sax.SAXException;
29  
30  import javax.swing.*;
31  import javax.xml.parsers.DocumentBuilder;
32  import javax.xml.parsers.DocumentBuilderFactory;
33  import javax.xml.parsers.FactoryConfigurationError;
34  import javax.xml.parsers.ParserConfigurationException;
35  import javax.xml.transform.*;
36  import javax.xml.transform.dom.DOMSource;
37  import javax.xml.transform.stream.StreamResult;
38  import java.awt.*;
39  import java.awt.event.ActionEvent;
40  import java.awt.event.ActionListener;
41  import java.io.*;
42  import java.net.HttpURLConnection;
43  import java.net.URL;
44  import java.util.Enumeration;
45  import java.util.Vector;
46  
47  public final class WebTools {
48  
49      private final static File url_template_file =
50              new File(System.getProperty("user.dir")+"/.URLTemplates.xml");
51      private static Vector journalTemplates = loadURLTemplates(url_template_file);
52      private static class URLTemplate {
53          private String journalRegExp, template;
54          private int minVolume = -1, maxVolume = -1;
55          private int minNumber = -1, maxNumber = -1;
56          private int minFirstpage = -1, maxFirstpage = -1;
57          private int minYear = -1, maxYear = -1;
58  
59          public URLTemplate(String journalRegExp, String template) {
60              this.journalRegExp=journalRegExp;
61              this.template=template;
62          }
63  
64          public void setMinVolume(int minV) { minVolume = minV; }
65          public void setMaxVolume(int maxV) { maxVolume = maxV; }
66  
67          public void setMinNumber(int minV) { minNumber = minV; }
68          public void setMaxNumber(int maxV) { maxNumber = maxV; }
69  
70          public void setMinFirstpage(int minV) { minFirstpage = minV; }
71          public void setMaxFirstpage(int maxV) { maxFirstpage = maxV; }
72  
73          public void setMinYear(int minV) { minYear = minV; }
74          public void setMaxYear(int maxV) { maxYear = maxV; }
75  
76          private boolean limitsOK(int minV, int maxV, String s) {
77              if ((minV<0) && (maxV<0)) { return true; }
78              if (s.length()==0) {
79                  // This is bad: the journal should specify this value
80                  // in order to find the url
81                  return false;
82              }
83              int v = Integer.parseInt(s);
84              if ((minV>=0) && (v<minV)) { return false; }
85              else if ((maxV>=0) && (v>maxV)) { return false; }
86              else { return true; }
87          }
88  
89          public String getRealURL(JournalEntry je) {
90              if (!je.getJournal().matches(journalRegExp)) { return null; }
91              else if (!(limitsOK(minVolume,maxVolume,je.getVolume()) &&
92                      limitsOK(minNumber,maxNumber,je.getVolume()) &&
93                      limitsOK(minFirstpage,maxFirstpage,je.getVolume()) &&
94                      limitsOK(minYear,maxYear,je.getVolume()))) {
95                  // all the limitsOK have to return true to get a match
96                  return null;
97              }
98  
99              String url = template;
100             if (url.indexOf("{")!=-1) {
101                 // Get all the {}
102                 String[] sp = url.split("(^|\\}).*?($|\\{)");
103                 for (int i = 0; i < sp.length; i++) {
104                     if (sp[i].length()==0) { continue; }
105                     String replacement="";
106                     if (sp[i].charAt(0)=='V') { replacement = je.getVolume(); }
107                     else if (sp[i].charAt(0)=='N') { replacement = je.getNumber(); }
108                     else if (sp[i].charAt(0)=='P') { replacement = je.getPages(); }
109                     else if (sp[i].charAt(0)=='Y') { replacement = je.getYear(); }
110                     else { throw new IllegalArgumentException("Invalid first letter in braces"); }
111                     if (sp[i].length()>1) {
112                         if (sp[i].charAt(1)!=',') { throw new IllegalArgumentException("Missing comma"); }
113                         // This is ok even if there is nothing after the comma:
114                         String rest = sp[i].substring(2);
115                         if (rest.length()>replacement.length()) {
116                             replacement =
117                                     rest.substring(0,rest.length()-replacement.length())+replacement;
118                         }
119                     }
120                     url=url.replaceFirst("\\{.*?\\}",replacement);
121                 }
122             }
123             //System.out.println("DEBUG INFO: URL = "+url);
124             return url;
125         }
126     }
127 
128     private static String username="", password="";
129     private static File configFile = new File(System.getProperty("user.dir")+"/.config.xml");
130     private static Vector proxies = loadProxies();
131 
132     private WebTools() {}
133 
134     private static void setProxy(String p) {
135         String proxyHost="", proxyPort="";
136         if (p!=null) {
137             if (p.indexOf(':')!=-1) {
138                 proxyHost = p.substring(0,p.indexOf(':'));
139                 proxyPort = p.substring(p.indexOf(':')+1);
140             }
141             else { proxyHost = p; }
142         }
143 
144         if (!proxyHost.equals("")) { System.setProperty("proxySet", "true" ); }
145         else { System.setProperty("proxySet", "false" ); }
146         System.setProperty("http.proxyHost", proxyHost );
147         System.setProperty("http.proxyPort", proxyPort );
148 
149         //System.getProperties().list(System.out);
150     }
151 
152     public static void configProxy() {
153         JOptionPane optionPane;
154         final JComboBox proxy = new JComboBox(proxies);
155         final JButton deleteHostNameButton = new JButton("Delete this host");
156         final JTextField usernameTF = new JTextField(username);
157         final JPasswordField passwordTF = new JPasswordField(password);
158 
159         proxy.setEditable(true);
160         proxy.addActionListener(new ActionListener() {
161             public void actionPerformed(ActionEvent e) {
162                 if (e.getActionCommand().equals("comboBoxEdited")) {
163                     String newProxy = (String) proxy.getSelectedItem();
164                     if (!newProxy.equals("")) {
165                         for (int i = proxy.getItemCount()-1; i >=0; i--) {
166                             if (proxy.getItemAt(i).equals(newProxy)) {
167                                 proxy.removeItemAt(i);
168                             }
169                         }
170                         proxy.insertItemAt(newProxy,0);
171                         deleteHostNameButton.setEnabled(true);
172                     }
173                     KeyboardFocusManager.getCurrentKeyboardFocusManager()
174                             .focusNextComponent(deleteHostNameButton);
175 
176                 }
177             }
178         });
179         if (proxies.size()==0) { deleteHostNameButton.setEnabled(false); }
180         deleteHostNameButton.addActionListener(new ActionListener() {
181             public void actionPerformed(ActionEvent e) {
182                 if (proxy.getItemCount()>0) {
183                     proxy.removeItemAt(proxy.getSelectedIndex());
184                 }
185                 if (proxy.getItemCount()==0) { deleteHostNameButton.setEnabled(false); }
186             }
187         });
188 
189         JPanel topPane = new JPanel();
190         topPane.setLayout(new GridLayout(0,1));
191         topPane.add(new JLabel("Enter Proxy:"));
192         topPane.add(new JLabel("(as my.proxy.com or my.proxy.com:portnumber)"));
193         topPane.add(proxy);
194         topPane.add(deleteHostNameButton);
195 
196         JPanel bottomPane = new JPanel();
197         bottomPane.setLayout(new GridLayout(0,2));
198         bottomPane.add(new JLabel("Username:"));
199         bottomPane.add(usernameTF);
200         bottomPane.add(new JLabel("Password:"));
201         bottomPane.add(passwordTF);
202 
203         Box whole = new Box(BoxLayout.Y_AXIS);
204         whole.add(topPane);
205         whole.add(bottomPane);
206 
207         optionPane = new JOptionPane(whole, JOptionPane.PLAIN_MESSAGE,
208                 JOptionPane.OK_CANCEL_OPTION);
209         JDialog dialog = optionPane.createDialog(null,"Enter Proxy Information");
210         dialog.setModal(true);
211         dialog.setResizable(true);
212         final Dimension winSize = new Dimension(500,300);
213         final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
214         final Point winLocation = new Point((screenSize.width-winSize.width)/2,(screenSize.height-winSize.height)/2);
215         dialog.setLocation(winLocation);
216         dialog.setSize(winSize);
217         dialog.show();
218 
219         if (((Integer) optionPane.getValue()).intValue() == JOptionPane.CANCEL_OPTION) {
220             return;
221         }
222 
223         proxies = new Vector();
224         if (proxy.getItemCount()>0) {
225             Object p = proxy.getSelectedItem();
226             proxy.removeItem(p);
227             proxy.insertItemAt(p,0);
228         }
229 
230         for (int i = 0; i < proxy.getItemCount(); i++) {
231             String t = (String) proxy.getItemAt(i);
232             if (!t.equals("")) { proxies.add(t); }
233         }
234 
235         if (proxies.size()>0) { setProxy((String) proxies.get(0)); }
236         else { setProxy(""); }
237 
238         username = usernameTF.getText();
239         password = new String(passwordTF.getPassword());
240 
241         saveProxies();
242     }
243 
244     private static Vector loadProxies() {
245         Vector loadedProxies = new Vector();
246         if (!configFile.exists()) { return loadedProxies; }
247         try {
248             DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
249             DocumentBuilder builder = factory.newDocumentBuilder();
250 
251             Document document = builder.parse( configFile );
252 
253             Element root = document.getDocumentElement();
254             root.normalize();
255 
256             if (!root.getTagName().equals("proxies")) {
257                 JOptionPane.showMessageDialog(null,
258                         "Invalid xml file: root node not 'proxies'", "ERROR",
259                         JOptionPane.ERROR_MESSAGE);
260                 return loadedProxies;
261             }
262 
263             NodeList proxyElements = root.getElementsByTagName("proxy");
264             for (int idx = 0; idx < proxyElements.getLength(); idx++) {
265                 Element e = (Element) proxyElements.item(idx);
266                 // Assuming the document has been normalized
267                 String proxyHost = e.getAttribute("host");
268                 if (proxyHost==null) { continue; }
269                 String proxyPort = e.getAttribute("port");
270                 if ((proxyPort!=null) && (!proxyPort.equals(""))) {
271                     proxyHost += ":"+proxyPort;
272                 }
273                 loadedProxies.add(proxyHost);
274             }
275             if (loadedProxies.size()>0) {
276                 setProxy((String) loadedProxies.get(0));
277             }
278         }
279         catch (ParserConfigurationException e) {
280             e.printStackTrace();
281         }
282         catch (SAXException e) {
283             JOptionPane.showMessageDialog(null,
284                     "Problem while parsing XML file (SAXException).",
285                     "ERROR", JOptionPane.ERROR_MESSAGE);
286             return null;
287         }
288         catch (FileNotFoundException e) {
289             JOptionPane.showMessageDialog(null,
290                     "File not found: "+e.getMessage(),
291                     "ERROR", JOptionPane.ERROR_MESSAGE);
292             return null;
293         }
294         catch (IOException e) {
295             e.printStackTrace();
296             return null;
297         }
298         return loadedProxies;
299     }
300 
301     private static void saveProxies() {
302         if (proxies.size()==0) {
303             configFile.delete();
304             return;
305         }
306         Document document;
307         try {
308             final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
309             final DocumentBuilder builder = factory.newDocumentBuilder();
310             document = builder.newDocument();
311 
312             Element proxyRoot = document.createElement("proxies");
313             for (int i = 0; i < proxies.size(); i++) {
314                 Element p = document.createElement("proxy");
315                 String t = (String) proxies.get(i);
316                 String proxyHost=null, proxyPort=null;
317                 if (t.indexOf(':')!=-1) {
318                     proxyHost = t.substring(0,t.indexOf(':'));
319                     proxyPort = t.substring(t.indexOf(':')+1);
320                 }
321                 else { proxyHost = t; }
322                 p.setAttribute("host",proxyHost);
323                 if (proxyPort!=null) { p.setAttribute("port",proxyPort); }
324                 proxyRoot.appendChild(p);
325             }
326             document.appendChild(proxyRoot);
327 
328             TransformerFactory tFactory = TransformerFactory.newInstance();
329             Transformer transformer = tFactory.newTransformer();
330 
331             //transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "JRefTree.dtd");
332             transformer.setOutputProperty(OutputKeys.INDENT, "yes");
333             Enumeration propertyNames = transformer.getOutputProperties().propertyNames();
334             while (propertyNames.hasMoreElements()) {
335                 String nextProp = propertyNames.nextElement().toString();
336                 if (nextProp.indexOf("indent-amount")>=0) {
337                     transformer.setOutputProperty(nextProp,"4");
338                     break;
339                 }
340             }
341 
342             DOMSource source = new DOMSource(document);
343             StreamResult result = new StreamResult(new FileWriter(configFile));
344             transformer.transform(source, result);
345         }
346         catch (FactoryConfigurationError factoryConfigurationError) {
347             factoryConfigurationError.printStackTrace();
348         }
349         catch (ParserConfigurationException e) {
350             e.printStackTrace();
351         }
352         catch (DOMException e) {
353             e.printStackTrace();
354         }
355         catch (TransformerFactoryConfigurationError transformerFactoryConfigurationError) {
356             transformerFactoryConfigurationError.printStackTrace();
357         }
358         catch (TransformerException e) {
359             e.printStackTrace();
360         }
361         catch (IllegalArgumentException e) {
362             e.printStackTrace();
363         }
364         catch (IOException e) {
365             JOptionPane.showMessageDialog(null,
366                     "Could not write file: "+e.getMessage(),
367                     "ERROR", JOptionPane.ERROR_MESSAGE);
368             return;
369         }
370     }
371 
372     private static String refSite(JournalEntry je) {
373         String url = null;
374         for (int i = 0; i < journalTemplates.size(); i++) {
375             url = ((URLTemplate) journalTemplates.elementAt(i)).getRealURL(je);
376             if (url!=null) { return url; }
377         }
378         return null;
379     }
380 
381     public static boolean downloadable(JournalEntry je) {
382         return (refSite(je)!=null);
383     }
384 
385     private static void setProxyAuthorization(HttpURLConnection uc) {
386         //if ( (username.length() > 0) ) { //&& (password.length()>0) ) {
387         String auth = username+":"+password;
388         String encodedAuth = base64encode( auth );
389         uc.setRequestProperty( "Proxy-Authorization", "Basic "+encodedAuth );
390         //}
391     }
392 
393     public static boolean downloadPaper(JournalEntry je) {
394         // Should not be necessary to check this:
395         if (je==null) { throw new NullPointerException("JournalEntry == null"); }
396 
397         String url = refSite(je);
398         if (url == null) { throw new NullPointerException("url == null"); }
399         String workingDir = System.getProperty("user.dir");
400         String filename = workingDir+"/papers/"+je.getEntryID()+".pdf";
401         PleaseWaitWindow pww = new PleaseWaitWindow();
402         try {
403             File file = new File(filename);
404             if (file.exists()) { throw new IOException("File exists"); }
405 
406             //System.out.println("DEBUG INFO: Attempting to download file: "+file.getName());
407             URL u = new URL(url);
408             HttpURLConnection uc;
409             boolean connectionOK = false, setProxyAuth = false, setCookie = false;
410             String cookie = "";
411             int maxCookies = 1;
412             do {
413                 uc = (HttpURLConnection) u.openConnection();
414                 // setRequestProperty needs to be done BEFORE connect, getInputStream, or getHeader
415                 if (setCookie) { uc.setRequestProperty("Cookie",cookie); }
416                 if (setProxyAuth) { setProxyAuthorization(uc); }
417                 uc.connect();
418                 int code = uc.getResponseCode();
419                 //System.out.println("DEBUG INFO: "+uc.getResponseMessage());
420                 if (code==HttpURLConnection.HTTP_OK) {
421                     // Check for cookies:
422                     cookie = uc.getHeaderField("Set-Cookie");
423                     if ((cookie == null) || (maxCookies==0)) { connectionOK = true; }
424                     else {
425                         int index = cookie.indexOf(";");
426                         if (index >=0 ) { cookie = cookie.substring(0,index); }
427                         setCookie=true;
428                         maxCookies--;
429                         //System.out.println("DEBUG INFO: Accepting cookie = " + cookie);
430                     }
431                 }
432                 else if (code == HttpURLConnection.HTTP_UNAUTHORIZED) {
433                     throw new IOException("Please configure proxy server");
434                 }
435                 else if (code == HttpURLConnection.HTTP_NOT_FOUND) {
436                     throw new IOException("Proxy host/port not found, please RE-configure");
437                 }
438                 else if (code == HttpURLConnection.HTTP_PROXY_AUTH) {
439                     if (!setProxyAuth) { setProxyAuth = true; }
440                     else {
441                         throw new IOException("Invalid proxy username/password combination.");
442                     }
443                 }
444                 else {
445                     throw new IOException(uc.getResponseMessage());
446                 }
447             } while (connectionOK == false);
448 
449             InputStream in = uc.getInputStream();
450             BufferedInputStream bis = new BufferedInputStream(in);
451             FileOutputStream fos = new FileOutputStream(file);
452             int cnt=1024*10, KbReceived = 0;
453             while (true) {
454                 int v = bis.read();
455                 if (v!=-1) { fos.write(v); cnt--; }
456                 else { break; }
457                 if (cnt==0) {
458                     KbReceived+=10;
459                     cnt=1024*10;
460                     pww.setText("  Downloaded "+KbReceived+" Kb");}
461             }
462             pww.setText("Download Finished");
463             bis.close();
464             fos.close();
465             in.close();
466         }
467         catch (IOException e) {
468             pww.dispose();
469             JOptionPane.showMessageDialog(null,"Download Failed:\n"+e.toString(),
470                     "ERROR", JOptionPane.ERROR_MESSAGE);
471             return false;
472         }
473 
474         pww.dispose();
475         return true;
476     }
477 
478     private static String base64encode(String s) {
479         if (s.equals("")) { return ""; }
480 
481         final String translationTable =
482                 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
483 
484         StringBuffer encodedString = new StringBuffer();
485 
486 
487         int leftOvers = s.length() % 3;
488 
489         String padding = "";
490         if (leftOvers==1) {
491             s+="\0\0";
492             padding = "==";
493         }
494         else if (leftOvers==2) {
495             s+="\0";
496             padding="=";
497         }
498         byte[] bytes = s.getBytes();
499         int chunksOfThree = bytes.length / 3;
500         int charactersAdded = 0;
501         for (int i = 0; i < chunksOfThree; i++) {
502             int ii = (bytes[i*3] << 16) + (bytes[i*3+1] << 8) + bytes[i*3+2];
503             encodedString.append(translationTable.charAt(ii >>> 18));
504             encodedString.append(translationTable.charAt((ii >>> 12) & 63));
505             encodedString.append(translationTable.charAt((ii >>> 6) & 63));
506             encodedString.append(translationTable.charAt(ii & 63));
507             charactersAdded += 4;
508             // add a newline for every 76 characters:
509             if ( (charactersAdded % 76) == 0 ) { encodedString.append("\n"); }
510         }
511         String trimmedString = encodedString.toString().trim();
512         String finalString = trimmedString.substring(
513                 0,trimmedString.length()-(padding.length())) + padding;
514 
515         return finalString;
516     }
517 
518     private static Vector loadURLTemplates(File file) {
519         if (!file.exists()) { saveURLTemplates(file); }
520         Vector journalTemplates = new Vector();
521         try {
522             DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
523             DocumentBuilder builder = factory.newDocumentBuilder();
524 
525             Document document = builder.parse( file );
526 
527             Element root = document.getDocumentElement();
528             root.normalize();
529 
530             if (!root.getTagName().equals("URL_Templates")) {
531                 JOptionPane.showMessageDialog(null,
532                         "Invalid xml file: root node not 'URL_Template'", "ERROR",
533                         JOptionPane.ERROR_MESSAGE);
534                 return null;
535             }
536 
537             NodeList templateElements = root.getElementsByTagName("template");
538             for (int idx = 0; idx < templateElements.getLength(); idx++) {
539                 Element e = (Element) templateElements.item(idx);
540                 // Assuming the document has been normalized
541                 Node textNode = e.getFirstChild();
542                 if (textNode==null) { continue; } // empty template
543                 URLTemplate ut = new URLTemplate(
544                         e.getAttribute("journal"), textNode.getNodeValue() );
545                 String att;
546                 if (!(att=e.getAttribute("minVolume")).equals("")) { ut.setMinVolume(Integer.parseInt(att)); }
547                 if (!(att=e.getAttribute("maxVolume")).equals("")) { ut.setMaxVolume(Integer.parseInt(att)); }
548                 if (!(att=e.getAttribute("minNumber")).equals("")) { ut.setMinNumber(Integer.parseInt(att)); }
549                 if (!(att=e.getAttribute("maxNumber")).equals("")) { ut.setMaxNumber(Integer.parseInt(att)); }
550                 if (!(att=e.getAttribute("minFirstpage")).equals("")) { ut.setMinFirstpage(Integer.parseInt(att)); }
551                 if (!(att=e.getAttribute("maxFirstpage")).equals("")) { ut.setMaxFirstpage(Integer.parseInt(att)); }
552                 if (!(att=e.getAttribute("minYear")).equals("")) { ut.setMinYear(Integer.parseInt(att)); }
553                 if (!(att=e.getAttribute("maxYear")).equals("")) { ut.setMaxYear(Integer.parseInt(att)); }
554 
555                 journalTemplates.add(ut);
556             }
557         }
558 //        catch (FactoryConfigurationError factoryConfigurationError) {
559 //            factoryConfigurationError.printStackTrace();
560 //        }
561         catch (ParserConfigurationException e) {
562             e.printStackTrace();
563         }
564         catch (SAXException e) {
565             JOptionPane.showMessageDialog(null,
566                     "Problem while parsing XML file (SAXException).",
567                     "ERROR", JOptionPane.ERROR_MESSAGE);
568             return null;
569         }
570         catch (FileNotFoundException e) {
571             JOptionPane.showMessageDialog(null,
572                     "File not found: "+e.getMessage(),
573                     "ERROR", JOptionPane.ERROR_MESSAGE);
574             return null;
575         }
576         catch (IOException e) {
577             e.printStackTrace();
578             return null;
579         }
580         return journalTemplates;
581     }
582 
583     private static void saveURLTemplates(File file){
584         if (file.exists()) { return; }
585 
586         Document document;
587         try {
588             final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
589             final DocumentBuilder builder = factory.newDocumentBuilder();
590             document = builder.newDocument();
591 
592             Element URLTemplateRoot = document.createElement("URL_Templates");
593             addTemplateElements(URLTemplateRoot, document);
594             document.appendChild(URLTemplateRoot);
595 
596             TransformerFactory tFactory = TransformerFactory.newInstance();
597             Transformer transformer = tFactory.newTransformer();
598 
599             //transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "JRefTree.dtd");
600             transformer.setOutputProperty(OutputKeys.INDENT, "yes");
601             Enumeration propertyNames = transformer.getOutputProperties().propertyNames();
602             while (propertyNames.hasMoreElements()) {
603                 String nextProp = propertyNames.nextElement().toString();
604                 if (nextProp.indexOf("indent-amount")>=0) {
605                     transformer.setOutputProperty(nextProp,"4");
606                     break;
607                 }
608             }
609             //transformer.getOutputProperties().list(System.out);
610 
611             DOMSource source = new DOMSource(document);
612             StreamResult result = new StreamResult(new FileWriter(file));
613             transformer.transform(source, result);
614         }
615         catch (FactoryConfigurationError factoryConfigurationError) {
616             factoryConfigurationError.printStackTrace();
617         }
618         catch (ParserConfigurationException e) {
619             e.printStackTrace();
620         }
621         catch (DOMException e) {
622             e.printStackTrace();
623         }
624         catch (TransformerFactoryConfigurationError transformerFactoryConfigurationError) {
625             transformerFactoryConfigurationError.printStackTrace();
626         }
627         catch (TransformerException e) {
628             e.printStackTrace();
629         }
630         catch (IllegalArgumentException e) {
631             e.printStackTrace();
632         }
633         catch (IOException e) {
634             JOptionPane.showMessageDialog(null,
635                     "Could not write file: "+e.getMessage(),
636                     "ERROR", JOptionPane.ERROR_MESSAGE);
637             return;
638         }
639     }
640 
641     private static void addTemplateElements(Element URLTemplateRoot, Document d) {
642         Element ut;
643 
644         URLTemplateRoot.appendChild(d.createComment(
645                 "   The main element is called 'URL_Templates'. It has no attributes.\n"+
646                 "   Within URL_Templates, there is only one kind of element: 'template'.\n"+
647                 "   This element must have the attribute 'journal', and can in addition\n"+
648                 "   have attributes 'minVolume', 'maxVolume', 'minIssue', 'maxIssue',\n"+
649                 "   'minFirstpage', 'maxFirstpage', 'minYear', and 'maxYear'.\n"+
650                 "   The 'journal' attribute can be a regular expressions (or just normal text).\n"+
651                 "   The other attributes are non-negative integers.\n"+
652                 "   The content of each 'template' element (between <template ...> and\n"+
653                 "   </template>) can include either {X} or {X,text},\n"+
654                 "   where X is one of V, N, P, Y (volume, number/issue, first page,\n"+
655                 "   and year, respectively). The 'text' is background text that the\n"+
656                 "   first part can overwrite. For example, say we have '{V,00000}',\n"+
657                 "   and assume that the volume is '86'. The result is then '00086'\n"+
658                 "   (if the volume was 123456, then the result would be just '123456').\n"+
659                 "   Another example: If template = 'http://prl.aps.org/v{V}/i{N}/p{P,abcdef}'\n"+
660                 "   and V='234', N='2', and P='99', we get 'http://prl.aps.org/v234/i2/pabcd99'."
661         ));
662 
663         // Phys. Rev. Lett.
664         ut = d.createElement("template");
665         ut.setAttribute("journal","(?i)Phys((ical)|\\.)? *Rev((iew)|\\.)? *Lett((ers?)|\\.)? *");
666         ut.setAttribute("maxVolume","83");
667         ut.appendChild(d.createTextNode("http://prola.aps.org/pdf/PRL/v{V}/"+
668                 "i{N}/p{P}_1"));
669         URLTemplateRoot.appendChild(ut);
670 
671         ut = d.createElement("template");
672         ut.setAttribute("journal","(?i)Phys((ical)|\\.)? *Rev((iew)|\\.)? *Lett((ers?)|\\.)? *");
673         ut.setAttribute("minVolume","84");
674         ut.setAttribute("maxVolume","999");
675         ut.appendChild(d.createTextNode(
676                 "http://ojps.aip.org/getpdf/servlet/GetPDFServlet?filetype=pdf&"+
677                 "id=PRLTAO{V,000000}{N,000000}{P,000000}000001&idtype=cvips"));
678         URLTemplateRoot.appendChild(ut);
679 
680         // Phys. Rev. A
681         ut = d.createElement("template");
682         ut.setAttribute("journal","(?i)Phys((ical)|\\.)? *Rev((iew)|\\.)? *A\\.? *");
683         ut.setAttribute("maxVolume","60");
684         ut.appendChild(d.createTextNode("http://prola.aps.org/pdf/PRA/v{V}/"+
685                 "i{N}/p{P}_1"));
686         URLTemplateRoot.appendChild(ut);
687 
688         ut = d.createElement("template");
689         ut.setAttribute("journal","(?i)Phys((ical)|\\.)? *Rev((iew)|\\.)? *A\\.? *");
690         ut.setAttribute("minVolume","61");
691         ut.setAttribute("maxVolume","999");
692         ut.appendChild(d.createTextNode(
693                 "http://ojps.aip.org/getpdf/servlet/GetPDFServlet?filetype=pdf&"+
694                 "id=PLRAAN{V,000000}{N,000000}{P,000000}000001&idtype=cvips"));
695         URLTemplateRoot.appendChild(ut);
696 
697         // Phys. Rev. B
698         ut = d.createElement("template");
699         ut.setAttribute("journal","(?i)Phys((ical)|\\.)? *Rev((iew)|\\.)? *B\\.? *");
700         ut.setAttribute("maxVolume","60");
701         ut.appendChild(d.createTextNode("http://prola.aps.org/pdf/PRB/v{V}/"+
702                 "i{N}/p{P}_1"));
703         URLTemplateRoot.appendChild(ut);
704 
705         ut = d.createElement("template");
706         ut.setAttribute("journal","(?i)Phys((ical)|\\.)? *Rev((iew)|\\.)? *B\\.? *");
707         ut.setAttribute("minVolume","61");
708         ut.setAttribute("maxVolume","999");
709         ut.appendChild(d.createTextNode(
710                 "http://ojps.aip.org/getpdf/servlet/GetPDFServlet?filetype=pdf&"+
711                 "id=PRBMDO{V,000000}{N,000000}{P,000000}000001&idtype=cvips"));
712         URLTemplateRoot.appendChild(ut);
713 
714         // Phys. Rev. C
715         ut = d.createElement("template");
716         ut.setAttribute("journal","(?i)Phys((ical)|\\.)? *Rev((iew)|\\.)? *C\\.? *");
717         ut.setAttribute("maxVolume","60");
718         ut.appendChild(d.createTextNode("http://prola.aps.org/pdf/PRC/v{V}/"+
719                 "i{N}/p{P}_1"));
720         URLTemplateRoot.appendChild(ut);
721 
722         ut = d.createElement("template");
723         ut.setAttribute("journal","(?i)Phys((ical)|\\.)? *Rev((iew)|\\.)? *C\\.? *");
724         ut.setAttribute("minVolume","61");
725         ut.setAttribute("maxVolume","999");
726         ut.appendChild(d.createTextNode(
727                 "http://ojps.aip.org/getpdf/servlet/GetPDFServlet?filetype=pdf&"+
728                 "id=PRVCAN{V,000000}{N,000000}{P,000000}000001&idtype=cvips"));
729         URLTemplateRoot.appendChild(ut);
730 
731         // Phys. Rev. D
732         ut = d.createElement("template");
733         ut.setAttribute("journal","(?i)Phys((ical)|\\.)? *Rev((iew)|\\.)? *D\\.? *");
734         ut.setAttribute("maxVolume","60");
735         ut.appendChild(d.createTextNode("http://prola.aps.org/pdf/PRD/v{V}/"+
736                 "i{N}/p{P}_1"));
737         URLTemplateRoot.appendChild(ut);
738 
739         ut = d.createElement("template");
740         ut.setAttribute("journal","(?i)Phys((ical)|\\.)? *Rev((iew)|\\.)? *D\\.? *");
741         ut.setAttribute("minVolume","61");
742         ut.setAttribute("maxVolume","999");
743         ut.appendChild(d.createTextNode(
744                 "http://ojps.aip.org/getpdf/servlet/GetPDFServlet?filetype=pdf&"+
745                 "id=PRVDAQ{V,000000}{N,000000}{P,000000}000001&idtype=cvips"));
746         URLTemplateRoot.appendChild(ut);
747 
748         // Phys. Rev. E
749         ut = d.createElement("template");
750         ut.setAttribute("journal","(?i)Phys((ical)|\\.)? *Rev((iew)|\\.)? *E\\.? *");
751         ut.setAttribute("maxVolume","60");
752         ut.appendChild(d.createTextNode("http://prola.aps.org/pdf/PRE/v{V}/"+
753                 "i{N}/p{P}_1"));
754         URLTemplateRoot.appendChild(ut);
755 
756         ut = d.createElement("template");
757         ut.setAttribute("journal","(?i)Phys((ical)|\\.)? *Rev((iew)|\\.)? *E\\.? *");
758         ut.setAttribute("minVolume","61");
759         ut.setAttribute("maxVolume","999");
760         ut.appendChild(d.createTextNode(
761                 "http://ojps.aip.org/getpdf/servlet/GetPDFServlet?filetype=pdf&"+
762                 "id=PLEEE8{V,000000}{N,000000}{P,000000}000001&idtype=cvips"));
763         URLTemplateRoot.appendChild(ut);
764 
765         // Rev. Mod. Phys.
766         ut = d.createElement("template");
767         ut.setAttribute("journal","(?i)Rev((iews)|\\.)? *(of)? *Mod((ern)|\\.)? *Phys((ics)|\\.)? *");
768         ut.setAttribute("maxVolume","71");
769         ut.appendChild(d.createTextNode("http://prola.aps.org/pdf/RMP/v{V}/"+
770                 "i{N}/p{P}_1"));
771         URLTemplateRoot.appendChild(ut);
772 
773         ut = d.createElement("template");
774         ut.setAttribute("journal","(?i)Rev((iews)|\\.)? *(of)? *Mod((ern)|\\.)? *Phys((ics)|\\.)? *");
775         ut.setAttribute("minVolume","72");
776         ut.setAttribute("maxVolume","999");
777         ut.appendChild(d.createTextNode(
778                 "http://ojps.aip.org/getpdf/servlet/GetPDFServlet?filetype=pdf&"+
779                 "id=RMPHAT{V,000000}{N,000000}{P,000000}000001&idtype=cvips"));
780         URLTemplateRoot.appendChild(ut);
781 
782         // Phys. Rev. Series II
783         ut = d.createElement("template");
784         ut.setAttribute("journal","(?i)Phys((ical)|\\.)? *Rev((iew)|\\.)? *");
785         ut.appendChild(d.createTextNode("http://prola.aps.org/pdf/PR/v{V}/"+
786                 "i{N}/p{P}_1"));
787         URLTemplateRoot.appendChild(ut);
788 
789         // Phys. Rev. Series I
790         ut = d.createElement("template");
791         ut.setAttribute("journal","(?i)Phys((ical)|\\.)? *Rev((iew)|\\.)? *I\\.? *");
792         ut.appendChild(d.createTextNode("http://prola.aps.org/pdf/PRI/v{V}/"+
793                 "i{N}/p{P}_1"));
794         URLTemplateRoot.appendChild(ut);
795     }
796 }