/**
  * Dereference a href and return the object if it is of the expected type.
  *
  * @return the resolved object
  * @param file the URI of the file in which the referenced element is located, used to absolutize
  *     references
  * @param href the reference to resolve
  * @param clazz the class of object expected
  */
 @SuppressWarnings("unchecked")
 protected <T> T dereferenceLocalHref(URI file, String href, Class<T> clazz) {
   Object o = null;
   String id = file.toString() + href.substring(href.indexOf('#'));
   o = idMap.get(id);
   if (o == null) {
     System.err.println(Wadl2JavaMessages.SKIPPING_REFERENCE(href, file.toString()));
     return null;
   } else if (!clazz.isInstance(o)) {
     System.err.println(Wadl2JavaMessages.SKIPPING_REFERENCE_TYPE(href, file.toString()));
     return null;
   }
   return (T) o;
 }
  /**
   * 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;
  }
  /**
   * Add a type to a resource. Follow references to types across WADL file boundaries
   *
   * @param href the identifier of the resource_type element to process
   * @param resource the resource
   * @param file the URI of the current WADL file being processed
   */
  protected void addTypeToResource(ResourceNode resource, String href, URI file) {
    // dereference resource
    if (!href.startsWith("#")) {
      // referecnce to element in another document
      file = getReferencedFile(file, href);
    }
    ResourceTypeNode n = ifaceMap.get(file.toString() + href.substring(href.indexOf('#')));

    if (n != null) {
      resource.addResourceType(n);
    } else {
      System.err.println(Wadl2JavaMessages.SKIPPING_REFERENCE(href, file.toString()));
    }
  }
 /**
  * Report an error.
  *
  * @param sAXParseException the exception that caused the error.
  */
 public void error(SAXParseException sAXParseException) {
   System.err.println(Wadl2JavaMessages.ERROR(sAXParseException.getMessage()));
 }
 /**
  * Report informative message
  *
  * @param sAXParseException the exception that caused the informative message.
  */
 public void info(SAXParseException sAXParseException) {
   System.err.println(Wadl2JavaMessages.INFO(sAXParseException.getMessage()));
 }
 /**
  * Report a warning
  *
  * @param sAXParseException the exception that caused the warning.
  */
 public void warning(SAXParseException sAXParseException) {
   System.err.println(Wadl2JavaMessages.WARNING(sAXParseException.getMessage()));
 }
  /**
   * Processes the previously set WADL file and generated code in the specified package and target
   * directory.
   *
   * @throws org.apache.tools.ant.BuildException if processing of the WADL file fails.
   */
  public void execute() throws BuildException {
    if (pkg == null) throw new BuildException(Wadl2JavaMessages.PACKAGE_ATTRIBUTE_REQUIRED());
    if (target == null) throw new BuildException(Wadl2JavaMessages.TARGET_ATTRIBUTE_REQUIRED());
    if (!target.exists())
      throw new BuildException(Wadl2JavaMessages.TARGET_DIRECTORY_MUST_EXIST(target.toString()));
    if (!target.isDirectory())
      throw new BuildException(Wadl2JavaMessages.TARGET_ATTRIBUTE_DIRECTORY(target.toString()));
    if (desc == null) throw new BuildException(Wadl2JavaMessages.DESCRIPTION_REQUIRED());

    List<File> customizations = new ArrayList<File>();
    for (FileSet fs : customizationFileSets) {
      DirectoryScanner ds = fs.getDirectoryScanner(getProject());
      String[] includedFiles = ds.getIncludedFiles();
      for (String filename : includedFiles) {
        File f = new File(ds.getBasedir(), filename);
        customizations.add(f);
      }
    }

    if (desc.getScheme() == null || desc.getScheme().equals("file")) {
      // assume a file if not explicitly told otherwise
      File fileDesc = new File(this.getOwningTarget().getProject().getBaseDir(), desc.getPath());
      if (!fileDesc.exists())
        throw new BuildException(Wadl2JavaMessages.WADL_DESCRIPTION_MUST_EXIST(desc.toString()));
      if (!fileDesc.isFile())
        throw new BuildException(Wadl2JavaMessages.WADL_DESCRIPTION_FILE(desc.toString()));
      desc = fileDesc.toURI();

      // check if description has changed since code was last generated
      long earliestProducedFileStamp = Long.MAX_VALUE;
      for (FileSet fs : producedFileSets) {
        DirectoryScanner ds = fs.getDirectoryScanner(getProject());
        String[] includedFiles = ds.getIncludedFiles();
        for (String filename : includedFiles) {
          File f = new File(ds.getBasedir(), filename);
          if (f.lastModified() < earliestProducedFileStamp)
            earliestProducedFileStamp = f.lastModified();
        }
      }
      long latestConsumedFileStamp = fileDesc.lastModified();
      for (FileSet fs : consumedFileSets) {
        DirectoryScanner ds = fs.getDirectoryScanner(getProject());
        String[] includedFiles = ds.getIncludedFiles();
        for (String filename : includedFiles) {
          File f = new File(ds.getBasedir(), filename);
          if (f.lastModified() > latestConsumedFileStamp)
            latestConsumedFileStamp = f.lastModified();
        }
      }
      for (File f : customizations) {
        if (f.lastModified() > latestConsumedFileStamp) latestConsumedFileStamp = f.lastModified();
      }

      if (earliestProducedFileStamp < Long.MAX_VALUE
          && latestConsumedFileStamp < earliestProducedFileStamp) {
        log(Wadl2JavaMessages.SKIPPING_COMPILATION());
        return;
      }
    }

    // pre-requisites satisfied, compile the description
    try {
      Wadl2Java wadlProcessor = new Wadl2Java(target, pkg, autoPackage, customizations);
      wadlProcessor.process(desc);
    } catch (Exception ex) {
      ex.printStackTrace();
      throw new BuildException(Wadl2JavaMessages.PROCESSING_FAILED(), ex);
    }
  }