private void writeConfig() {
    try {
      // Write the contents to a new file first such that we don't clobber the
      // existing file if some I/O error occurs.
      File file =
          new File(mConfigFile.getParentFile(), mConfigFile.getName() + ".new"); // $NON-NLS-1$

      Writer writer = new BufferedWriter(new FileWriter(file));
      writer.write(
          "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
              + //$NON-NLS-1$
              "<lint>\n"); //$NON-NLS-1$

      if (!mSuppressed.isEmpty() || !mSeverity.isEmpty()) {
        // Process the maps in a stable sorted order such that if the
        // files are checked into version control with the project,
        // there are no random diffs just because hashing algorithms
        // differ:
        Set<String> idSet = new HashSet<String>();
        for (String id : mSuppressed.keySet()) {
          idSet.add(id);
        }
        for (String id : mSeverity.keySet()) {
          idSet.add(id);
        }
        List<String> ids = new ArrayList<String>(idSet);
        Collections.sort(ids);

        for (String id : ids) {
          writer.write("    <"); // $NON-NLS-1$
          writer.write(TAG_ISSUE);
          writeAttribute(writer, ATTR_ID, id);
          Severity severity = mSeverity.get(id);
          if (severity != null) {
            writeAttribute(writer, ATTR_SEVERITY, severity.name().toLowerCase(Locale.US));
          }

          List<Pattern> regexps = mRegexps != null ? mRegexps.get(id) : null;
          List<String> paths = mSuppressed.get(id);
          if (paths != null && !paths.isEmpty() || regexps != null && !regexps.isEmpty()) {
            writer.write('>');
            writer.write('\n');
            // The paths are already kept in sorted order when they are modified
            // by ignore(...)
            if (paths != null) {
              for (String path : paths) {
                writer.write("        <"); // $NON-NLS-1$
                writer.write(TAG_IGNORE);
                writeAttribute(writer, ATTR_PATH, path.replace('\\', '/'));
                writer.write(" />\n"); // $NON-NLS-1$
              }
            }
            if (regexps != null) {
              for (Pattern regexp : regexps) {
                writer.write("        <"); // $NON-NLS-1$
                writer.write(TAG_IGNORE);
                writeAttribute(writer, ATTR_REGEXP, regexp.pattern());
                writer.write(" />\n"); // $NON-NLS-1$
              }
            }
            writer.write("    </"); // $NON-NLS-1$
            writer.write(TAG_ISSUE);
            writer.write('>');
            writer.write('\n');
          } else {
            writer.write(" />\n"); // $NON-NLS-1$
          }
        }
      }

      writer.write("</lint>"); // $NON-NLS-1$
      writer.close();

      // Move file into place: move current version to lint.xml~ (removing the old ~ file
      // if it exists), then move the new version to lint.xml.
      File oldFile =
          new File(mConfigFile.getParentFile(), mConfigFile.getName() + '~'); // $NON-NLS-1$
      if (oldFile.exists()) {
        oldFile.delete();
      }
      if (mConfigFile.exists()) {
        mConfigFile.renameTo(oldFile);
      }
      boolean ok = file.renameTo(mConfigFile);
      if (ok && oldFile.exists()) {
        oldFile.delete();
      }
    } catch (Exception e) {
      mClient.log(e, null);
    }
  }
  private void readConfig() {
    mSuppressed = new HashMap<String, List<String>>();
    mSeverity = new HashMap<String, Severity>();

    if (!mConfigFile.exists()) {
      return;
    }

    try {
      Document document = XmlUtils.parseUtfXmlFile(mConfigFile, false);
      NodeList issues = document.getElementsByTagName(TAG_ISSUE);
      Splitter splitter = Splitter.on(',').trimResults().omitEmptyStrings();
      for (int i = 0, count = issues.getLength(); i < count; i++) {
        Node node = issues.item(i);
        Element element = (Element) node;
        String idList = element.getAttribute(ATTR_ID);
        if (idList.isEmpty()) {
          formatError("Invalid lint config file: Missing required issue id attribute");
          continue;
        }
        Iterable<String> ids = splitter.split(idList);

        NamedNodeMap attributes = node.getAttributes();
        for (int j = 0, n = attributes.getLength(); j < n; j++) {
          Node attribute = attributes.item(j);
          String name = attribute.getNodeName();
          String value = attribute.getNodeValue();
          if (ATTR_ID.equals(name)) {
            // already handled
          } else if (ATTR_SEVERITY.equals(name)) {
            for (Severity severity : Severity.values()) {
              if (value.equalsIgnoreCase(severity.name())) {
                for (String id : ids) {
                  mSeverity.put(id, severity);
                }
                break;
              }
            }
          } else {
            formatError("Unexpected attribute \"%1$s\"", name);
          }
        }

        // Look up ignored errors
        NodeList childNodes = element.getChildNodes();
        if (childNodes.getLength() > 0) {
          for (int j = 0, n = childNodes.getLength(); j < n; j++) {
            Node child = childNodes.item(j);
            if (child.getNodeType() == Node.ELEMENT_NODE) {
              Element ignore = (Element) child;
              String path = ignore.getAttribute(ATTR_PATH);
              if (path.isEmpty()) {
                String regexp = ignore.getAttribute(ATTR_REGEXP);
                if (regexp.isEmpty()) {
                  formatError(
                      "Missing required attribute %1$s or %2$s under %3$s",
                      ATTR_PATH, ATTR_REGEXP, idList);
                } else {
                  addRegexp(idList, ids, n, regexp, false);
                }
              } else {
                // Normalize path format to File.separator. Also
                // handle the file format containing / or \.
                if (File.separatorChar == '/') {
                  path = path.replace('\\', '/');
                } else {
                  path = path.replace('/', File.separatorChar);
                }

                if (path.indexOf('*') != -1) {
                  String regexp = globToRegexp(path);
                  addRegexp(idList, ids, n, regexp, false);
                } else {
                  for (String id : ids) {
                    List<String> paths = mSuppressed.get(id);
                    if (paths == null) {
                      paths = new ArrayList<String>(n / 2 + 1);
                      mSuppressed.put(id, paths);
                    }
                    paths.add(path);
                  }
                }
              }
            }
          }
        }
      }
    } catch (SAXParseException e) {
      formatError(e.getMessage());
    } catch (Exception e) {
      mClient.log(e, null);
    }
  }