Clover coverage report - DrJava Test Coverage (drjava-20120304-r5456)
Coverage timestamp: Sun Mar 4 2012 03:13:23 CST
file stats: LOC: 411   Methods: 16
NCLOC: 277   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
XMLProjectFileParser.java 50% 82.9% 75% 79.7%
coverage coverage
 1    /*BEGIN_COPYRIGHT_BLOCK
 2    *
 3    * Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu)
 4    * All rights reserved.
 5    *
 6    * Redistribution and use in source and binary forms, with or without
 7    * modification, are permitted provided that the following conditions are met:
 8    * * Redistributions of source code must retain the above copyright
 9    * notice, this list of conditions and the following disclaimer.
 10    * * Redistributions in binary form must reproduce the above copyright
 11    * notice, this list of conditions and the following disclaimer in the
 12    * documentation and/or other materials provided with the distribution.
 13    * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
 14    * names of its contributors may be used to endorse or promote products
 15    * derived from this software without specific prior written permission.
 16    *
 17    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18    * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 19    * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 20    * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 21    * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 22    * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 23    * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 24    * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 25    * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 26    * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 27    * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28    *
 29    * This software is Open Source Initiative approved Open Source Software.
 30    * Open Source Initative Approved is a trademark of the Open Source Initiative.
 31    *
 32    * This file is part of DrJava. Download the current version of this project
 33    * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
 34    *
 35    * END_COPYRIGHT_BLOCK*/
 36   
 37    package edu.rice.cs.drjava.project;
 38   
 39    import java.io.*;
 40    import java.util.List;
 41    import java.util.ArrayList;
 42    import java.util.Map;
 43    import java.util.HashMap;
 44    import java.util.Date;
 45    import java.text.SimpleDateFormat;
 46    import org.w3c.dom.Node;
 47   
 48    import edu.rice.cs.util.AbsRelFile;
 49    import edu.rice.cs.plt.tuple.Pair;
 50    import edu.rice.cs.drjava.model.DummyDocumentRegion;
 51    import edu.rice.cs.drjava.model.FileRegion;
 52    import edu.rice.cs.drjava.model.debug.DebugWatchData;
 53    import edu.rice.cs.drjava.model.debug.DebugBreakpointData;
 54    import edu.rice.cs.util.XMLConfig;
 55    import edu.rice.cs.drjava.project.MalformedProjectFileException;
 56    import edu.rice.cs.util.StringOps;
 57    import edu.rice.cs.plt.text.TextUtil;
 58   
 59    import edu.rice.cs.drjava.config.Option;
 60    import edu.rice.cs.drjava.config.OptionMap;
 61    import edu.rice.cs.drjava.config.OptionParser;
 62    import edu.rice.cs.drjava.config.OptionParseException;
 63    import edu.rice.cs.drjava.DrJava;
 64   
 65    import static edu.rice.cs.util.XMLConfig.XMLConfigException;
 66   
 67    import edu.rice.cs.plt.text.TextUtil;
 68   
 69    /** This parser loads XML configuration files using the XMLConfig class in the util package.
 70    *
 71    * <p> If at some point new information is to be stored in the project file, the following places in the code that need to
 72    * changed: <menu> <li> If the new information pertains to a document, the DocFile class should be augmented to
 73    * store the new info. <li> The interface for the DocumentInfoGetter should be expanded to allow for the new
 74    * data to be retrieved. <li> Add a new clause to the else-if ladder in the FilePropertyVisitor. <li>
 75    * Add the new information to the DocFile form the DocumentInfoGetter in the ProjectFileBuilder's
 76    * addSourceDocument method.</p>
 77    *
 78    * <p> If the change is at the top level, you must modify the evaluateExpression method in this parser and add the
 79    * corresponding methods to the ProjectFileIR, ProjectFileIRImpl, and ProjectFileBuilder</p>
 80    */
 81    public class XMLProjectFileParser extends ProjectFileParserFacade {
 82    /** Singleton instance of XMLProjectFileParser */
 83    public static final XMLProjectFileParser ONLY = new XMLProjectFileParser();
 84  3 private XMLProjectFileParser() { _xmlProjectFile = true; }
 85   
 86    protected String _parent;
 87    protected String _srcFileBase;
 88    protected XMLConfig _xc;
 89   
 90    static edu.rice.cs.util.Log LOG = new edu.rice.cs.util.Log("xmlparser.log", false);
 91   
 92    /** @param projFile the file to parse
 93    * @return the project file IR
 94    */
 95  4 public ProjectFileIR parse(File projFile) throws IOException, FileNotFoundException, MalformedProjectFileException {
 96  4 _projectFile = projFile;
 97  4 _parent = projFile.getParent();
 98  4 _srcFileBase = _parent;
 99  4 ProjectFileIR pfir = new ProjectProfile(projFile);
 100   
 101  4 try {
 102  4 XMLConfig xcParent = new XMLConfig(projFile);
 103   
 104    // read version... this string isn't actually used
 105  4 String version = xcParent.get("drjava.version", "unknown");
 106  4 LOG.log("version = '" + version + "'");
 107   
 108  4 pfir.setDrJavaVersion(version);
 109   
 110    // create a sub-configuration so we don't have to prefix everything with "drjava/project/"
 111  4 _xc = new XMLConfig(xcParent, xcParent.getNodes("drjava/project").get(0));
 112  4 LOG.log(_xc.toString());
 113  4 String s;
 114   
 115    // read project root; must be present
 116  4 try {
 117  4 s = _xc.get(".root");
 118  4 LOG.log("root = '" + s + "'");
 119  4 File root = new File(_parent, s);
 120  4 LOG.log("_parent = " + _parent);
 121  4 pfir.setProjectRoot(root);
 122  4 _srcFileBase = root.getCanonicalPath();
 123  4 LOG.log("_srcFileBase from reading the prject root = " + _srcFileBase);
 124    }
 125  0 catch(XMLConfigException e) { throw new MalformedProjectFileException("XML Parse Error: " + e.getMessage() + "\n" + StringOps.getStackTrace(e)); }
 126   
 127    // read create jar options
 128  4 try {
 129  4 s = _xc.get("createjar.file");
 130  4 LOG.log("createjar.file = '" + s + "'");
 131  4 File jarFile = new File(_parent, s);
 132  4 pfir.setCreateJarFile(jarFile);
 133    }
 134    catch(XMLConfigException e) { /* not present is ok too */ }
 135  4 try {
 136  4 s = _xc.get("createjar.flags");
 137  1 LOG.log("createjar.flags = '" + s + "'");
 138  1 int flags = Integer.valueOf(s);
 139  1 pfir.setCreateJarFlags(flags);
 140    }
 141    catch(XMLConfigException e) { /* not present is ok too */ }
 142   
 143  4 try{
 144  4 s = _xc.get(".manifest");
 145  0 LOG.log("manifest = '" + s + "'");
 146  0 pfir.setCustomManifest(TextUtil.xmlUnescape(s));
 147    }catch(XMLConfigException e) { /* not present is fine */ }
 148   
 149    // read build dir
 150  4 try {
 151  4 s = _xc.get(".build");
 152  3 LOG.log("build = '" + s + "'");
 153  3 File buildDir = (!new File(s).isAbsolute())?new File(_parent, s):new File(s);
 154  3 pfir.setBuildDirectory(buildDir);
 155    }
 156    catch(XMLConfigException e) { /* not present is ok too */ }
 157   
 158    // read working dir; must be present
 159  4 try {
 160  4 s = _xc.get(".work");
 161  4 LOG.log("work = '" + s + "'");
 162  4 File workDir = (!new File(s).isAbsolute())?new File(_parent, s):new File(s);
 163  4 pfir.setWorkingDirectory(workDir);
 164    }
 165  0 catch(XMLConfigException e) { throw new MalformedProjectFileException("XML Parse Error: " + e.getMessage() + "\n" + StringOps.getStackTrace(e)); }
 166   
 167    // read main class
 168  4 try {
 169  4 s = _xc.get(".main");
 170  3 LOG.log("main = '" + s + "'");
 171    /*File mainClass = new File(_parent, s);
 172    pfir.setMainClass(mainClass);*/
 173  3 pfir.setMainClass(s);
 174    }
 175    catch(XMLConfigException e) { /* not present is ok too */ }
 176   
 177  4 try {
 178  4 s = _xc.get(".autorefresh");
 179  3 boolean b = Boolean.valueOf(s);
 180  3 pfir.setAutoRefreshStatus(b);
 181    }
 182    catch(XMLConfigException e) { /* not important */}
 183   
 184  4 try { // must all be present
 185    // read source files and included files
 186   
 187  4 pfir.setSourceFiles(readSourceFiles("source", _srcFileBase));
 188  4 pfir.setAuxiliaryFiles(readSourceFiles("included", ""));
 189   
 190    // read excluded files
 191  4 pfir.setExcludedFiles(readSourceFiles("excluded", ""));
 192   
 193   
 194    // read collapsed paths
 195  4 pfir.setCollapsedPaths(readCollapsed());
 196   
 197    // read class paths
 198  4 pfir.setClassPaths(readFiles("classpath", _srcFileBase));
 199   
 200    // read breakpoints
 201  4 pfir.setBreakpoints(readBreakpoints());
 202   
 203    // read watches
 204  4 pfir.setWatches(readWatches());
 205   
 206    // read bookmarks
 207  4 pfir.setBookmarks(readBookmarks());
 208   
 209    // read stored preferences
 210  4 pfir.setPreferencesStoredInProject(readStoredPreferences());
 211    }
 212  0 catch(XMLConfigException e) { throw new MalformedProjectFileException("XML Parse Error: " + e.getMessage() + "\n" + StringOps.getStackTrace(e)); }
 213    }
 214    catch(XMLConfigException e) {
 215  0 throw new MalformedProjectFileException("Malformed XML project file." + e.getMessage() + "\n" + StringOps.getStackTrace(e));
 216    }
 217    catch(NumberFormatException e) {
 218  0 throw new MalformedProjectFileException("Malformed XML project file; a value that should have been an integer was not.\n" + StringOps.getStackTrace(e));
 219    }
 220    catch(IllegalArgumentException e) {
 221  0 throw new MalformedProjectFileException("Malformed XML project file; a value had the wrong type.\n" + StringOps.getStackTrace(e));
 222    }
 223    catch(IndexOutOfBoundsException e) {
 224  0 throw new MalformedProjectFileException("Malformed XML project file; a required value was missing.\n" + StringOps.getStackTrace(e));
 225    }
 226  4 LOG.log(pfir.toString());
 227  4 return pfir;
 228    }
 229   
 230  12 protected List<DocFile> readSourceFiles(String path, String rootPath) throws MalformedProjectFileException {
 231  12 LOG.log("readSourceFiles(path='" + path + "', rootPath='" + rootPath + "')");
 232  12 List<DocFile> docFList = new ArrayList<DocFile>();
 233  12 List<Node> defs = _xc.getNodes(path + "/file");
 234  12 LOG.log("\tdefs.size() = " + defs.size());
 235  25 for(Node n: defs) { LOG.log("\t" + n.getNodeValue()); }
 236   
 237  12 for(Node n: defs) {
 238  25 LOG.log("\t" + n.toString());
 239   
 240    // now all path names are relative to node n...
 241  25 String name = _xc.get(".name",n);
 242  25 LOG.log("\t\tname = '" + name + "'");
 243   
 244  25 int selectFrom = _xc.getInt("select.from",n);
 245  25 int selectTo = _xc.getInt("select.to",n);
 246  25 LOG.log("\t\tselect = '" + selectFrom + " to " + selectTo + "'");
 247   
 248  25 int scrollCol = _xc.getInt("scroll.column",n);
 249  25 int scrollRow = _xc.getInt("scroll.row",n);
 250  25 LOG.log("\t\tscroll = '" + scrollCol + " , " + scrollRow + "'");
 251   
 252  25 String timestamp = _xc.get(".timestamp",n);
 253  25 LOG.log("\t\ttimestamp = '" + timestamp + "'");
 254  25 Date modDate;
 255  25 try {
 256    // attemp parsing in default locale
 257  25 modDate = ProjectProfile.MOD_DATE_FORMAT.parse(timestamp); }
 258    catch (java.text.ParseException e1) {
 259    // parsing in default locale failed
 260  0 try {
 261    // attempt parsing in current locale
 262  0 modDate = new SimpleDateFormat(ProjectProfile.MOD_DATE_FORMAT_STRING).parse(timestamp);
 263    }
 264    catch (java.text.ParseException e2) {
 265    // both parsings failed
 266  0 throw new MalformedProjectFileException("Source file node contains badly formatted timestamp.");
 267    }
 268    }
 269   
 270  25 String pkg = _xc.get(".package",n);
 271  25 LOG.log("\t\tpackage = '" + pkg + "'");
 272   
 273  25 boolean active;
 274  25 try {
 275  25 active = _xc.getBool(".active",n);
 276  4 LOG.log("\t\tactive = '" + active + "'");
 277    }
 278  21 catch(XMLConfigException e) { active = false; /* it's ok if it doesn't exist */ }
 279   
 280    /* added to check if file path name refers to absolute. Intended to eliminate project errors over network paths */
 281  25 Boolean absName = (new File(name)).isAbsolute();
 282   
 283  25 DocFile docF = new DocFile(((rootPath.length() > 0 && !absName)?new File(rootPath,name):new File(name)).getAbsoluteFile(),
 284    new Pair<Integer,Integer>(selectFrom,selectTo),
 285    new Pair<Integer,Integer>(scrollCol,scrollCol),
 286    active,
 287    pkg);
 288  25 docF.setSavedModDate(modDate.getTime());
 289  25 docFList.add(docF);
 290    }
 291  12 return docFList;
 292    }
 293   
 294  0 protected List<AbsRelFile> readFiles(String path) {
 295  0 return readFiles(path, "");
 296    }
 297   
 298  4 protected List<AbsRelFile> readFiles(String path, String rootPath) {
 299  4 List<AbsRelFile> fList = new ArrayList<AbsRelFile>();
 300  4 List<Node> defs = _xc.getNodes(path + "/file");
 301  4 for(Node n: defs) {
 302    // now all path names are relative to node n...
 303  4 String name = _xc.get(".name",n);
 304  4 boolean abs = _xc.getBool(".absolute",n,true); // default to true for backward compatibility
 305   
 306    /* added to check if file path name refers to absolute. Intended to eliminate project errors over network paths */
 307  4 abs |= (new File(name)).isAbsolute();
 308   
 309  4 AbsRelFile f = new AbsRelFile(((rootPath.length() > 0 && !abs)?
 310    new File(rootPath,name):
 311    new File(name)).getAbsoluteFile(),abs);
 312  4 fList.add(f);
 313    }
 314  4 return fList;
 315    }
 316   
 317  4 protected List<String> readCollapsed() {
 318  4 List<String> pList = new ArrayList<String>();
 319  4 List<Node> defs = _xc.getNodes("collapsed/path");
 320  4 for(Node n: defs) {
 321    // now all path names are relative to node n...
 322  4 pList.add(_xc.get(".name", n));
 323    }
 324  4 return pList;
 325    }
 326   
 327  4 protected List<DebugBreakpointData> readBreakpoints() {
 328  4 List<DebugBreakpointData> bpList = new ArrayList<DebugBreakpointData>();
 329  4 List<Node> defs = _xc.getNodes("breakpoints/breakpoint");
 330  4 for(Node n: defs) {
 331    // now all path names are relative to node n...
 332  3 String name = _xc.get(".file", n);
 333  3 final int lnr = _xc.getInt(".line", n);
 334  3 final boolean enabled = _xc.getBool(".enabled", n);
 335  3 DebugBreakpointData dbd;
 336  3 if ((_srcFileBase == null) || (new File(name).isAbsolute())) {
 337  0 final File f = new File(name);
 338  0 dbd = new DebugBreakpointData() {
 339  0 public File getFile() { return f; }
 340  0 public int getLineNumber() { return lnr; }
 341  0 public boolean isEnabled() { return enabled; }
 342    };
 343    }
 344    else {
 345  3 final File f = new File(_srcFileBase, name);
 346  3 dbd = new DebugBreakpointData() {
 347  3 public File getFile() { return f; }
 348  3 public int getLineNumber() { return lnr; }
 349  3 public boolean isEnabled() { return enabled; }
 350    };
 351    }
 352  3 bpList.add(dbd);
 353    }
 354  4 return bpList;
 355    }
 356   
 357  4 protected List<DebugWatchData> readWatches() {
 358  4 List<DebugWatchData> wList = new ArrayList<DebugWatchData>();
 359  4 List<Node> defs = _xc.getNodes("watches/watch");
 360  4 for(Node n: defs) {
 361    // now all path names are relative to node n...
 362  2 wList.add(new DebugWatchData(_xc.get(".name", n)));
 363    }
 364  4 return wList;
 365    }
 366   
 367  4 protected List<FileRegion> readBookmarks() {
 368  4 List<FileRegion> rList = new ArrayList<FileRegion>();
 369  4 List<Node> defs = _xc.getNodes("bookmarks/bookmark");
 370  4 for(Node n: defs) {
 371    // now all path names are relative to node n...
 372  2 String name = _xc.get(".file", n);
 373  2 final int from = _xc.getInt(".from", n);
 374  2 final int to = _xc.getInt(".to", n);
 375  2 File f;
 376  0 if ((_srcFileBase == null) || (new File(name).isAbsolute())) { f = new File(name); }
 377  2 else { f = new File(_srcFileBase, name); }
 378  2 rList.add(new DummyDocumentRegion(f, from, to));
 379    }
 380  4 return rList;
 381    }
 382   
 383  4 @SuppressWarnings("unchecked")
 384    protected Map<OptionParser<?>,String> readStoredPreferences() {
 385  4 HashMap<OptionParser<?>,String> storedPreferences = new HashMap<OptionParser<?>,String>();
 386  4 List<Node> prefs = _xc.getNodes("preferences/preference");
 387   
 388  4 for(Node n: prefs) {
 389    // now all path names are relative to node n...
 390  0 String name = TextUtil.xmlUnescape(_xc.get(".name", n));
 391  0 String value = TextUtil.xmlUnescape(_xc.get(".value", n));
 392   
 393  0 OptionMap map = DrJava.getConfig().getOptionMap();
 394  0 for (OptionParser<?> option : map.keys()) {
 395  0 if (option.name.equals(name)) {
 396  0 try {
 397  0 map.setString(option, value);
 398  0 storedPreferences.put(option, value);
 399  0 if (option instanceof Option) {
 400  0 DrJava.getConfig().setSetting((Option)option, map.getOption(option));
 401    }
 402    }
 403    catch(OptionParseException ope) { /* ignore, just do not restore */ }
 404  0 break;
 405    }
 406    }
 407    }
 408   
 409  4 return storedPreferences;
 410    }
 411    }