/**
   * Process the root WADL file and generate code.
   *
   * @param rootDesc the URI of the WADL file to process
   * @throws javax.xml.bind.JAXBException if the WADL file is invalid, a referenced WADL file is
   *     invalid, or if the code generator encounters a problem.
   * @throws java.io.IOException if the specified WADL file cannot be read.
   * @throws com.sun.codemodel.JClassAlreadyExistsException if, during code generation, the WADL
   *     processor attempts to create a duplicate class. This indicates a structural problem with
   *     the WADL file, e.g. duplicate peer resource entries.
   */
  public void process(URI rootDesc)
      throws JAXBException, IOException, JClassAlreadyExistsException {
    // read in root WADL file
    JAXBContext jbc =
        JAXBContext.newInstance("org.jvnet.ws.wadl", this.getClass().getClassLoader());
    u = jbc.createUnmarshaller();
    s2j = new SchemaCompilerImpl();
    errorListener = new SchemaCompilerErrorListener();
    if (!autoPackage) s2j.setDefaultPackageName(pkg);
    s2j.setErrorListener(errorListener);
    idMap = new HashMap<String, Object>();
    ifaceMap = new HashMap<String, ResourceTypeNode>();
    Application a = processDescription(rootDesc);
    ResourceNode r = buildAst(a, rootDesc);

    // generate code
    s2jModel = s2j.bind();
    if (s2jModel != null) {
      codeModel = s2jModel.generateCode(null, errorListener);
      Iterator<JPackage> packages = codeModel.packages();
      StringBuilder buf = new StringBuilder();
      while (packages.hasNext()) {
        JPackage genPkg = packages.next();
        if (!genPkg.isDefined("ObjectFactory")) continue;
        if (buf.length() > 0) buf.append(':');
        buf.append(genPkg.name());
      }
      generatedPackages = buf.toString();
      jPkg = codeModel._package(pkg);
      generateResourceTypeInterfaces();
      generateEndpointClass(r);
      codeModel.build(outputDir);
    }
  }
 private static void registerNamespace(SchemaCompiler sc, String namespace, String pkgName)
     throws Exception {
   Document doc = XMLUtils.newDocument();
   Element rootElement = doc.createElement("schema");
   rootElement.setAttribute("xmlns", "http://www.w3.org/2001/XMLSchema");
   rootElement.setAttribute("xmlns:jaxb", "http://java.sun.com/xml/ns/jaxb");
   rootElement.setAttribute("jaxb:version", "2.0");
   rootElement.setAttribute("targetNamespace", namespace);
   Element annoElement = doc.createElement("annotation");
   Element appInfo = doc.createElement("appinfo");
   Element schemaBindings = doc.createElement("jaxb:schemaBindings");
   Element pkgElement = doc.createElement("jaxb:package");
   pkgElement.setAttribute("name", pkgName);
   annoElement.appendChild(appInfo);
   appInfo.appendChild(schemaBindings);
   schemaBindings.appendChild(pkgElement);
   rootElement.appendChild(annoElement);
   File file = File.createTempFile("customized", ".xsd");
   FileOutputStream stream = new FileOutputStream(file);
   try {
     Result result = new StreamResult(stream);
     Transformer xformer = TransformerFactory.newInstance().newTransformer();
     xformer.transform(new DOMSource(rootElement), result);
     stream.flush();
     stream.close();
   } catch (Exception e) {
     log.error(e);
   }
   InputSource ins = new InputSource(file.toURI().toString());
   sc.parseSchema(ins);
   // file.delete();
   deleteFile(file);
 }
  private static void scanEpisodeFile(File jar, SchemaCompiler sc)
      throws BadCommandLineException, IOException {

    URLClassLoader ucl = new URLClassLoader(new URL[] {jar.toURL()});
    Enumeration<URL> resources = ucl.findResources("META-INF/sun-jaxb.episode");
    while (resources.hasMoreElements()) {
      URL url = resources.nextElement();
      sc.getOptions().addBindFile(new InputSource(url.toExternalForm()));
    }
  }
  /**
   * 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;
  }
  /**
   * @param additionalSchemas
   * @throws RuntimeException
   */
  public static TypeMapper processSchemas(
      final List schemas, Element[] additionalSchemas, CodeGenConfiguration cgconfig)
      throws RuntimeException {
    try {

      // check for the imported types. Any imported types are supposed to be here also
      if (schemas == null || schemas.isEmpty()) {
        // there are no types to be code generated
        // However if the type mapper is left empty it will be a problem for the other
        // processes. Hence the default type mapper is set to the configuration
        return new DefaultTypeMapper();
      }

      final Map schemaToInputSourceMap = new HashMap();
      final Map<String, StringBuffer> publicIDToStringMap = new HashMap<String, StringBuffer>();

      // create the type mapper
      JavaTypeMapper mapper = new JavaTypeMapper();

      String baseURI = cgconfig.getBaseURI();
      if (!baseURI.endsWith("/")) {
        baseURI = baseURI + "/";
      }

      for (int i = 0; i < schemas.size(); i++) {
        XmlSchema schema = (XmlSchema) schemas.get(i);
        InputSource inputSource = new InputSource(new StringReader(getSchemaAsString(schema)));
        // here we have to set a proper system ID. otherwise when processing the
        // included schaemas for this schema we have a problem
        // it creates the system ID using this target namespace value

        inputSource.setSystemId(baseURI + "xsd" + i + ".xsd");
        inputSource.setPublicId(schema.getTargetNamespace());
        schemaToInputSourceMap.put(schema, inputSource);
      }

      File outputDir = new File(cgconfig.getOutputLocation(), "src");
      // outputDir.mkdir();
      createDir(outputDir);

      Map nsMap = cgconfig.getUri2PackageNameMap();
      EntityResolver resolver =
          new EntityResolver() {
            public InputSource resolveEntity(String publicId, String systemId)
                throws SAXException, IOException {
              InputSource returnInputSource = null;
              XmlSchema key = null;
              for (Iterator iter = schemaToInputSourceMap.keySet().iterator(); iter.hasNext(); ) {
                key = (XmlSchema) iter.next();
                String nsp = key.getTargetNamespace();
                if (nsp != null && nsp.equals(publicId)) {

                  // when returning the input stream we have to always return a new
                  // input stream.
                  // sinc jaxbri internally consumes the input stream it gives an
                  // exception.
                  returnInputSource = new InputSource(new StringReader(getSchemaAsString(key)));
                  InputSource existingInputSource = (InputSource) schemaToInputSourceMap.get(key);
                  returnInputSource.setSystemId(existingInputSource.getSystemId());
                  returnInputSource.setPublicId(existingInputSource.getPublicId());
                  break;
                }
              }
              if (returnInputSource == null) {
                // then we have to find this using the file system
                if (systemId != null) {
                  returnInputSource = new InputSource(systemId);
                  returnInputSource.setSystemId(systemId);
                }
              }

              if (returnInputSource == null) {
                if (publicId != null) {

                  if (!publicIDToStringMap.containsKey(publicId)) {
                    URL url = new URL(publicId);
                    BufferedReader bufferedReader =
                        new BufferedReader(new InputStreamReader(url.openStream()));
                    StringBuffer stringBuffer = new StringBuffer();
                    String str = null;
                    while ((str = bufferedReader.readLine()) != null) {
                      stringBuffer.append(str);
                    }
                    publicIDToStringMap.put(publicId, stringBuffer);
                  }

                  String schemaString = publicIDToStringMap.get(publicId).toString();
                  returnInputSource = new InputSource(new StringReader(schemaString));
                  returnInputSource.setPublicId(publicId);
                  returnInputSource.setSystemId(publicId);
                }
              }
              return returnInputSource;
            }
          };

      Map properties = cgconfig.getProperties();
      String bindingFileName = (String) properties.get(BINDING_FILE_NAME);

      XmlSchema key = null;
      for (Iterator schemaIter = schemaToInputSourceMap.keySet().iterator();
          schemaIter.hasNext(); ) {

        SchemaCompiler sc = XJC.createSchemaCompiler();
        if (bindingFileName != null) {
          if (bindingFileName.endsWith(".jar")) {
            scanEpisodeFile(new File(bindingFileName), sc);
          } else {
            InputSource inputSoruce = new InputSource(new FileInputStream(bindingFileName));
            inputSoruce.setSystemId(new File(bindingFileName).toURI().toString());
            sc.getOptions().addBindFile(inputSoruce);
          }
        }

        key = (XmlSchema) schemaIter.next();

        if (nsMap != null) {
          Iterator iterator = nsMap.entrySet().iterator();
          while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            String namespace = (String) entry.getKey();
            String pkg = (String) nsMap.get(namespace);
            registerNamespace(sc, namespace, pkg);
          }
        }

        sc.setEntityResolver(resolver);

        sc.setErrorListener(
            new ErrorListener() {
              public void error(SAXParseException saxParseException) {
                log.error(saxParseException.getMessage());
                log.debug(saxParseException.getMessage(), saxParseException);
              }

              public void fatalError(SAXParseException saxParseException) {
                log.error(saxParseException.getMessage());
                log.debug(saxParseException.getMessage(), saxParseException);
              }

              public void warning(SAXParseException saxParseException) {
                log.warn(saxParseException.getMessage());
                log.debug(saxParseException.getMessage(), saxParseException);
              }

              public void info(SAXParseException saxParseException) {
                log.info(saxParseException.getMessage());
                log.debug(saxParseException.getMessage(), saxParseException);
              }
            });

        sc.parseSchema((InputSource) schemaToInputSourceMap.get(key));
        sc.getOptions().addGrammar((InputSource) schemaToInputSourceMap.get(key));

        for (Object property : properties.keySet()) {
          String propertyName = (String) property;
          if (propertyName.startsWith("X")) {
            String[] args = null;
            String propertyValue = (String) properties.get(property);
            if (propertyValue != null) {
              args = new String[] {"-" + propertyName, propertyValue};
            } else {
              args = new String[] {"-" + propertyName};
            }
            sc.getOptions().parseArguments(args);
          }
        }

        // Bind the XML
        S2JJAXBModel jaxbModel = sc.bind();

        if (jaxbModel == null) {
          throw new RuntimeException("Unable to generate code using jaxbri");
        }

        // Code change to sort Object factory classes start -SOA2.8
        sortGeneratedObjectFactoryClasses(jaxbModel);
        // Code change to sort Object factory classes end -SOA2.8

        // Emit the code artifacts
        JCodeModel codeModel = jaxbModel.generateCode(null, null);
        FileCodeWriter writer = new FileCodeWriter(outputDir);
        codeModel.build(writer);

        Collection mappings = jaxbModel.getMappings();

        Iterator iter = mappings.iterator();

        while (iter.hasNext()) {
          Mapping mapping = (Mapping) iter.next();
          QName qn = mapping.getElement();
          String typeName = mapping.getType().getTypeClass().fullName();

          mapper.addTypeMappingName(qn, typeName);
        }

        // process the unwrapped parameters
        if (!cgconfig.isParametersWrapped()) {
          // figure out the unwrapped operations
          List axisServices = cgconfig.getAxisServices();
          for (Iterator servicesIter = axisServices.iterator(); servicesIter.hasNext(); ) {
            AxisService axisService = (AxisService) servicesIter.next();
            for (Iterator operations = axisService.getOperations(); operations.hasNext(); ) {
              AxisOperation op = (AxisOperation) operations.next();

              if (WSDLUtil.isInputPresentForMEP(op.getMessageExchangePattern())) {
                AxisMessage message = op.getMessage(WSDLConstants.MESSAGE_LABEL_IN_VALUE);
                if (message != null && message.getParameter(Constants.UNWRAPPED_KEY) != null) {

                  Mapping mapping = jaxbModel.get(message.getElementQName());
                  List elementProperties = mapping.getWrapperStyleDrilldown();
                  for (int j = 0; j < elementProperties.size(); j++) {
                    Property elementProperty = (Property) elementProperties.get(j);

                    QName partQName =
                        WSDLUtil.getPartQName(
                            op.getName().getLocalPart(),
                            WSDLConstants.INPUT_PART_QNAME_SUFFIX,
                            elementProperty.elementName().getLocalPart());
                    // this type is based on a primitive type- use the
                    // primitive type name in this case
                    String fullJaveName = elementProperty.type().fullName();
                    if (elementProperty.type().isArray()) {
                      fullJaveName = fullJaveName.concat("[]");
                    }
                    mapper.addTypeMappingName(partQName, fullJaveName);

                    if (elementProperty.type().isPrimitive()) {
                      mapper.addTypeMappingStatus(partQName, Boolean.TRUE);
                    }
                    if (elementProperty.type().isArray()) {
                      mapper.addTypeMappingStatus(partQName, Constants.ARRAY_TYPE);
                    }
                  }
                }
              }

              if (WSDLUtil.isOutputPresentForMEP(op.getMessageExchangePattern())) {
                AxisMessage message = op.getMessage(WSDLConstants.MESSAGE_LABEL_OUT_VALUE);
                if (message != null && message.getParameter(Constants.UNWRAPPED_KEY) != null) {

                  Mapping mapping = jaxbModel.get(message.getElementQName());
                  List elementProperties = mapping.getWrapperStyleDrilldown();
                  for (int j = 0; j < elementProperties.size(); j++) {
                    Property elementProperty = (Property) elementProperties.get(j);

                    QName partQName =
                        WSDLUtil.getPartQName(
                            op.getName().getLocalPart(),
                            WSDLConstants.OUTPUT_PART_QNAME_SUFFIX,
                            elementProperty.elementName().getLocalPart());
                    // this type is based on a primitive type- use the
                    // primitive type name in this case
                    String fullJaveName = elementProperty.type().fullName();
                    if (elementProperty.type().isArray()) {
                      fullJaveName = fullJaveName.concat("[]");
                    }
                    mapper.addTypeMappingName(partQName, fullJaveName);

                    if (elementProperty.type().isPrimitive()) {
                      mapper.addTypeMappingStatus(partQName, Boolean.TRUE);
                    }
                    if (elementProperty.type().isArray()) {
                      mapper.addTypeMappingStatus(partQName, Constants.ARRAY_TYPE);
                    }
                  }
                }
              }
            }
          }
        }
      }

      // Return the type mapper
      return mapper;

    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }