/**
   * 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);
    }
  }
  /**
   * @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);
    }
  }