/**
   * Build a map of all method, representation, fault and resource elements that have an ID. These
   * are used to dereference href values when building the ast.
   *
   * @param desc the URI of the WADL file being processed
   * @param a the root element of an unmarshalled WADL document
   * @throws javax.xml.bind.JAXBException if the WADL file is invalid or if the code generator
   *     encounters a problem.
   * @throws java.io.IOException if the specified WADL file cannot be read.
   */
  @SuppressWarnings("unchecked")
  protected void buildIDMap(Application a, URI desc) throws JAXBException, IOException {
    // process globally declared items
    for (Object child : a.getResourceTypeOrMethodOrRepresentation()) {
      if (child instanceof Method) extractMethodIds((Method) child, desc);
      else if (child instanceof ResourceType) extractResourceTypeIds((ResourceType) child, desc);
      else {
        JAXBElement<RepresentationType> repOrFault = (JAXBElement<RepresentationType>) child;
        extractRepresentationId(repOrFault.getValue(), desc);
      }
    }

    // process resource hierarchy
    if (a.getResources() != null)
      for (Resource r : a.getResources().getResource()) extractResourceIds(r, desc);
  }
  /**
   * Unmarshall a WADL file, process any schemas referenced in the WADL file, add any items with an
   * ID to a global ID map, and follow any references to additional WADL files.
   *
   * @param desc the URI of the description file
   * @return the unmarshalled WADL application element
   * @throws javax.xml.bind.JAXBException if the WADL file is invalid or if the code generator
   *     encounters a problem.
   * @throws java.io.IOException if the specified WADL file cannot be read.
   */
  public Application processDescription(URI desc) throws JAXBException, IOException {
    // check for files that have already been processed to prevent loops
    if (processedDocs.contains(desc.toString())) return null;
    processedDocs.add(desc.toString());

    // read in WADL file
    System.out.println(Wadl2JavaMessages.PROCESSING(desc.toString()));
    Application a = (Application) u.unmarshal(desc.toURL());

    // process embedded schemas
    Grammars g = a.getGrammars();
    if (g != null) {
      for (Include i : g.getInclude()) {
        URI incl = desc.resolve(i.getHref());
        if (processedDocs.contains(incl.toString())) continue;
        processedDocs.add(incl.toString());
        System.out.println(Wadl2JavaMessages.PROCESSING(incl.toString()));
        InputSource input = new InputSource(incl.toURL().openStream());
        input.setSystemId(incl.toString());
        s2j.parseSchema(input);
      }
      int embeddedSchemaNo = 0; // used to generate unique system ID
      for (Object any : g.getAny()) {
        if (any instanceof Element) {
          Element element = (Element) any;
          s2j.parseSchema(
              desc.toString() + "#schema" + Integer.toString(embeddedSchemaNo), element);
          embeddedSchemaNo++;
        }
      }
    }
    for (File customization : customizations) {
      URI incl = desc.resolve(customization.toURI());
      System.out.println(Wadl2JavaMessages.PROCESSING(incl.toString()));
      InputSource input = new InputSource(incl.toURL().openStream());
      input.setSystemId(incl.toString());
      s2j.parseSchema(input);
    }
    buildIDMap(a, desc);
    return a;
  }
  /**
   * Build an abstract tree from an unmarshalled WADL file
   *
   * @param a the application element of the root WADL file
   * @param rootFile the URI of the root WADL file. Other WADL files might be included by reference.
   * @return the resource element that corresponds to the root of the resource tree
   */
  protected ResourceNode buildAst(Application a, URI rootFile) {
    for (String ifaceId : ifaceMap.keySet()) {
      buildResourceTypes(ifaceId, a);
    }

    Resources r = a.getResources();
    ResourceNode n = new ResourceNode(a, r);
    if (r != null) {
      for (Resource child : r.getResource()) {
        buildResourceTree(n, child, rootFile);
      }
    }

    return n;
  }