@Override
  public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
    final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
    if (!JaxrsDeploymentMarker.isJaxrsDeployment(deploymentUnit)) {
      return;
    }
    final DeploymentUnit parent =
        deploymentUnit.getParent() == null ? deploymentUnit : deploymentUnit.getParent();
    final Map<ModuleIdentifier, ResteasyDeploymentData> deploymentData;
    if (deploymentUnit.getParent() == null) {
      deploymentData =
          Collections.synchronizedMap(new HashMap<ModuleIdentifier, ResteasyDeploymentData>());
      deploymentUnit.putAttachment(
          JaxrsAttachments.ADDITIONAL_RESTEASY_DEPLOYMENT_DATA, deploymentData);
    } else {
      deploymentData = parent.getAttachment(JaxrsAttachments.ADDITIONAL_RESTEASY_DEPLOYMENT_DATA);
    }

    final ModuleIdentifier moduleIdentifier =
        deploymentUnit.getAttachment(Attachments.MODULE_IDENTIFIER);

    ResteasyDeploymentData resteasyDeploymentData = new ResteasyDeploymentData();
    final WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
    final Module module = deploymentUnit.getAttachment(Attachments.MODULE);

    try {

      if (warMetaData == null) {
        resteasyDeploymentData.setScanAll(true);
        scan(deploymentUnit, module.getClassLoader(), resteasyDeploymentData);
        deploymentData.put(moduleIdentifier, resteasyDeploymentData);
      } else {
        scanWebDeployment(
            deploymentUnit,
            warMetaData.getMergedJBossWebMetaData(),
            module.getClassLoader(),
            resteasyDeploymentData);
        scan(deploymentUnit, module.getClassLoader(), resteasyDeploymentData);
      }
      deploymentUnit.putAttachment(
          JaxrsAttachments.RESTEASY_DEPLOYMENT_DATA, resteasyDeploymentData);
    } catch (ModuleLoadException e) {
      throw new DeploymentUnitProcessingException(e);
    }
  }
  protected void scanWebDeployment(
      final DeploymentUnit du,
      final JBossWebMetaData webdata,
      final ClassLoader classLoader,
      final ResteasyDeploymentData resteasyDeploymentData)
      throws DeploymentUnitProcessingException {

    // If there is a resteasy boot class in web.xml, then the default should be to not scan
    // make sure this call happens before checkDeclaredApplicationClassAsServlet!!!
    boolean hasBoot = hasBootClasses(webdata);
    resteasyDeploymentData.setBootClasses(hasBoot);

    Class<?> declaredApplicationClass =
        checkDeclaredApplicationClassAsServlet(webdata, classLoader);
    // Assume that checkDeclaredApplicationClassAsServlet created the dispatcher
    if (declaredApplicationClass != null) {
      resteasyDeploymentData.setDispatcherCreated(true);
    }

    // set scanning on only if there are no boot classes
    if (!hasBoot && !webdata.isMetadataComplete()) {
      resteasyDeploymentData.setScanAll(true);
      resteasyDeploymentData.setScanProviders(true);
      resteasyDeploymentData.setScanResources(true);
    }

    // check resteasy configuration flags

    List<ParamValueMetaData> contextParams = webdata.getContextParams();

    if (contextParams != null) {
      for (ParamValueMetaData param : contextParams) {
        if (param.getParamName().equals(RESTEASY_SCAN)) {
          resteasyDeploymentData.setScanAll(valueOf(RESTEASY_SCAN, param.getParamValue()));
        } else if (param.getParamName().equals(ResteasyContextParameters.RESTEASY_SCAN_PROVIDERS)) {
          resteasyDeploymentData.setScanProviders(
              valueOf(RESTEASY_SCAN_PROVIDERS, param.getParamValue()));
        } else if (param.getParamName().equals(RESTEASY_SCAN_RESOURCES)) {
          resteasyDeploymentData.setScanResources(
              valueOf(RESTEASY_SCAN_RESOURCES, param.getParamValue()));
        } else if (param
            .getParamName()
            .equals(ResteasyContextParameters.RESTEASY_UNWRAPPED_EXCEPTIONS)) {
          resteasyDeploymentData.setUnwrappedExceptionsParameterSet(true);
        }
      }
    }
  }
  protected void scan(
      final DeploymentUnit du,
      final ClassLoader classLoader,
      final ResteasyDeploymentData resteasyDeploymentData)
      throws DeploymentUnitProcessingException, ModuleLoadException {

    final CompositeIndex index = du.getAttachment(Attachments.COMPOSITE_ANNOTATION_INDEX);

    if (!resteasyDeploymentData.shouldScan()) {
      return;
    }

    final Set<ClassInfo> applicationClass = index.getAllKnownSubclasses(APPLICATION);
    try {
      if (applicationClass.size() > 1) {
        StringBuilder builder = new StringBuilder();
        Set<ClassInfo> aClasses = new HashSet<ClassInfo>();
        for (ClassInfo c : applicationClass) {
          if (!Modifier.isAbstract(c.flags())) {
            aClasses.add(c);
          }
          builder.append(" ").append(c.name().toString());
        }
        if (aClasses.size() > 1) {
          throw new DeploymentUnitProcessingException(
              MESSAGES.onlyOneApplicationClassAllowed(builder));
        } else if (aClasses.size() == 1) {
          ClassInfo aClass = applicationClass.iterator().next();
          resteasyDeploymentData.setScannedApplicationClass(
              (Class<? extends Application>) classLoader.loadClass(aClass.name().toString()));
        }
      } else if (applicationClass.size() == 1) {
        ClassInfo aClass = applicationClass.iterator().next();
        resteasyDeploymentData.setScannedApplicationClass(
            (Class<? extends Application>) classLoader.loadClass(aClass.name().toString()));
      }
    } catch (ClassNotFoundException e) {
      throw MESSAGES.cannotLoadApplicationClass(e);
    }

    List<AnnotationInstance> resources = null;
    List<AnnotationInstance> providers = null;
    if (resteasyDeploymentData.isScanResources()) {
      resources = index.getAnnotations(JaxrsAnnotations.PATH.getDotName());
    }
    if (resteasyDeploymentData.isScanProviders()) {
      providers = index.getAnnotations(JaxrsAnnotations.PROVIDER.getDotName());
    }

    if ((resources == null || resources.isEmpty()) && (providers == null || providers.isEmpty()))
      return;
    final Set<ClassInfo> pathInterfaces = new HashSet<ClassInfo>();
    if (resources != null) {
      for (AnnotationInstance e : resources) {
        final ClassInfo info;
        if (e.target() instanceof ClassInfo) {
          info = (ClassInfo) e.target();
        } else if (e.target() instanceof MethodInfo) {
          // ignore
          continue;
        } else {
          JAXRS_LOGGER.classOrMethodAnnotationNotFound("@Path", e.target());
          continue;
        }
        if (!Modifier.isInterface(info.flags())) {
          resteasyDeploymentData.getScannedResourceClasses().add(info.name().toString());
        } else {
          pathInterfaces.add(info);
        }
      }
    }
    if (providers != null) {
      for (AnnotationInstance e : providers) {
        if (e.target() instanceof ClassInfo) {
          ClassInfo info = (ClassInfo) e.target();
          if (!Modifier.isInterface(info.flags())) {
            resteasyDeploymentData.getScannedProviderClasses().add(info.name().toString());
          }
        } else {
          JAXRS_LOGGER.classAnnotationNotFound("@Provider", e.target());
        }
      }
    }

    // look for all implementations of interfaces annotated @Path
    for (final ClassInfo iface : pathInterfaces) {
      final Set<ClassInfo> implementors = index.getAllKnownImplementors(iface.name());
      for (final ClassInfo implementor : implementors) {
        resteasyDeploymentData.getScannedResourceClasses().add(implementor.name().toString());
      }
    }
  }
  @Override
  public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
    final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();

    if (!JaxrsDeploymentMarker.isJaxrsDeployment(deploymentUnit)) {
      return;
    }

    if (!DeploymentTypeMarker.isType(DeploymentType.WAR, deploymentUnit)) {
      return;
    }

    final DeploymentUnit parent =
        deploymentUnit.getParent() == null ? deploymentUnit : deploymentUnit.getParent();
    final WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
    final JBossWebMetaData webdata = warMetaData.getMergedJBossWebMetaData();

    final ResteasyDeploymentData resteasy =
        deploymentUnit.getAttachment(JaxrsAttachments.RESTEASY_DEPLOYMENT_DATA);

    if (resteasy == null) return;

    // remove the resteasy.scan parameter
    // because it is not needed
    final List<ParamValueMetaData> params = webdata.getContextParams();
    if (params != null) {
      Iterator<ParamValueMetaData> it = params.iterator();
      while (it.hasNext()) {
        final ParamValueMetaData param = it.next();
        if (param.getParamName().equals(RESTEASY_SCAN)) {
          it.remove();
        } else if (param.getParamName().equals(RESTEASY_SCAN_RESOURCES)) {
          it.remove();
        } else if (param.getParamName().equals(RESTEASY_SCAN_PROVIDERS)) {
          it.remove();
        }
      }
    }

    final Map<ModuleIdentifier, ResteasyDeploymentData> attachmentMap =
        parent.getAttachment(JaxrsAttachments.ADDITIONAL_RESTEASY_DEPLOYMENT_DATA);
    final List<ResteasyDeploymentData> additionalData = new ArrayList<ResteasyDeploymentData>();
    final ModuleSpecification moduleSpec =
        deploymentUnit.getAttachment(Attachments.MODULE_SPECIFICATION);
    if (moduleSpec != null && attachmentMap != null) {
      final Set<ModuleIdentifier> identifiers = new HashSet<ModuleIdentifier>();
      for (ModuleDependency dep : moduleSpec.getAllDependencies()) {
        // make sure we don't double up
        if (!identifiers.contains(dep.getIdentifier())) {
          identifiers.add(dep.getIdentifier());
          if (attachmentMap.containsKey(dep.getIdentifier())) {
            additionalData.add(attachmentMap.get(dep.getIdentifier()));
          }
        }
      }
      resteasy.merge(additionalData);
    }
    if (!resteasy.getScannedResourceClasses().isEmpty()) {
      StringBuffer buf = null;
      for (String resource : resteasy.getScannedResourceClasses()) {
        if (buf == null) {
          buf = new StringBuffer();
          buf.append(resource);
        } else {
          buf.append(",").append(resource);
        }
      }
      String resources = buf.toString();
      JAXRS_LOGGER.debugf("Adding JAX-RS resource classes: %s", resources);
      setContextParameter(webdata, ResteasyContextParameters.RESTEASY_SCANNED_RESOURCES, resources);
    }
    if (!resteasy.getScannedProviderClasses().isEmpty()) {
      StringBuffer buf = null;
      for (String provider : resteasy.getScannedProviderClasses()) {
        if (buf == null) {
          buf = new StringBuffer();
          buf.append(provider);
        } else {
          buf.append(",").append(provider);
        }
      }
      String providers = buf.toString();
      JAXRS_LOGGER.debugf("Adding JAX-RS provider classes: %s", providers);
      setContextParameter(webdata, ResteasyContextParameters.RESTEASY_SCANNED_PROVIDERS, providers);
    }

    if (!resteasy.getScannedJndiComponentResources().isEmpty()) {
      StringBuffer buf = null;
      for (String resource : resteasy.getScannedJndiComponentResources()) {
        if (buf == null) {
          buf = new StringBuffer();
          buf.append(resource);
        } else {
          buf.append(",").append(resource);
        }
      }
      String providers = buf.toString();
      JAXRS_LOGGER.debugf("Adding JAX-RS jndi component resource classes: %s", providers);
      setContextParameter(
          webdata, ResteasyContextParameters.RESTEASY_SCANNED_JNDI_RESOURCES, providers);
    }

    if (!resteasy.isUnwrappedExceptionsParameterSet()) {
      setContextParameter(
          webdata,
          ResteasyContextParameters.RESTEASY_UNWRAPPED_EXCEPTIONS,
          "javax.ejb.EJBException");
    }

    if (resteasy.hasBootClasses() || resteasy.isDispatcherCreated()) return;

    boolean useScannedClass = false;
    String servletName;
    if (resteasy.getScannedApplicationClass() == null) {
      // if there is no scanned application we must add a servlet with a name of
      // javax.ws.rs.core.Application
      JBossServletMetaData servlet = new JBossServletMetaData();
      servlet.setName(JAX_RS_SERVLET_NAME);
      servlet.setServletClass(HttpServlet30Dispatcher.class.getName());
      servlet.setAsyncSupported(true);
      addServlet(webdata, servlet);
      servletName = JAX_RS_SERVLET_NAME;

    } else {
      if (servletMappingsExist(webdata, JAX_RS_SERVLET_NAME)) {
        throw new DeploymentUnitProcessingException(MESSAGES.conflictUrlMapping());
      }

      // now there are two options.
      // if there is already a servlet defined with an init param
      // we don't do anything.
      // Otherwise we install our filter
      // JAVA-RS seems somewhat confused about the difference between a context param
      // and an init param.
      ParamValueMetaData param = findInitParam(webdata, SERVLET_INIT_PARAM);
      if (param != null) {
        // we need to promote the init param to a context param
        servletName = param.getParamValue();
        setContextParameter(webdata, "javax.ws.rs.Application", servletName);
      } else {
        ParamValueMetaData contextParam = findContextParam(webdata, "javax.ws.rs.Application");
        if (contextParam == null) {
          setContextParameter(
              webdata, "javax.ws.rs.Application", resteasy.getScannedApplicationClass().getName());
          useScannedClass = true;
          servletName = resteasy.getScannedApplicationClass().getName();
        } else {
          servletName = contextParam.getParamValue();
        }
      }
    }

    boolean mappingSet = false;

    if (useScannedClass) {

      // look for servlet mappings
      if (!servletMappingsExist(webdata, servletName)) {
        // no mappings, add our own
        List<String> patterns = new ArrayList<String>();
        if (resteasy.getScannedApplicationClass().isAnnotationPresent(ApplicationPath.class)) {
          ApplicationPath path =
              resteasy.getScannedApplicationClass().getAnnotation(ApplicationPath.class);
          String pathValue = path.value().trim();
          if (!pathValue.startsWith("/")) {
            pathValue = "/" + pathValue;
          }
          String prefix = pathValue;
          if (pathValue.endsWith("/")) {
            pathValue += "*";
          } else {
            pathValue += "/*";
          }
          patterns.add(pathValue);
          setContextParameter(webdata, "resteasy.servlet.mapping.prefix", prefix);
          mappingSet = true;
        } else {
          JAXRS_LOGGER.noServletMappingFound(servletName);
          return;
        }
        ServletMappingMetaData mapping = new ServletMappingMetaData();
        mapping.setServletName(servletName);
        mapping.setUrlPatterns(patterns);
        if (webdata.getServletMappings() == null) {
          webdata.setServletMappings(new ArrayList<ServletMappingMetaData>());
        }
        webdata.getServletMappings().add(mapping);
      }

      // add a servlet named after the application class
      JBossServletMetaData servlet = new JBossServletMetaData();
      servlet.setName(servletName);
      servlet.setServletClass(HttpServlet30Dispatcher.class.getName());
      servlet.setAsyncSupported(true);
      addServlet(webdata, servlet);
    }

    if (!mappingSet) {
      // now we need tell resteasy it's relative path
      final List<ServletMappingMetaData> mappings = webdata.getServletMappings();
      if (mappings != null) {
        for (final ServletMappingMetaData mapping : mappings) {
          if (mapping.getServletName().equals(servletName)) {
            if (mapping.getUrlPatterns() != null) {
              for (String pattern : mapping.getUrlPatterns()) {
                if (mappingSet) {
                  JAXRS_LOGGER.moreThanOneServletMapping(servletName, pattern);
                } else {
                  mappingSet = true;
                  String realPattern = pattern;
                  if (realPattern.endsWith("*")) {
                    realPattern = realPattern.substring(0, realPattern.length() - 1);
                  }
                  setContextParameter(webdata, "resteasy.servlet.mapping.prefix", realPattern);
                }
              }
            }
          }
        }
      }
    }
  }
  @Override
  public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
    final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();

    final Module module =
        deploymentUnit.getAttachment(org.jboss.as.server.deployment.Attachments.MODULE);
    if (module == null) {
      return;
    }

    final ResteasyDeploymentData resteasy =
        deploymentUnit.getAttachment(JaxrsAttachments.RESTEASY_DEPLOYMENT_DATA);
    if (resteasy == null) {
      return;
    }
    // right now I only support resources
    if (!resteasy.isScanResources()) return;

    final EEModuleDescription moduleDescription =
        deploymentUnit.getAttachment(Attachments.EE_MODULE_DESCRIPTION);
    if (moduleDescription == null) {
      return;
    }

    final ClassLoader loader = module.getClassLoader();

    for (final ComponentDescription component : moduleDescription.getComponentDescriptions()) {
      Class<?> componentClass = null;
      try {
        componentClass = loader.loadClass(component.getComponentClassName());
      } catch (ClassNotFoundException e) {
        throw new DeploymentUnitProcessingException(e);
      }
      if (!GetRestful.isRootResource(componentClass)) continue;

      if (component instanceof SessionBeanComponentDescription) {
        Class[] jaxrsType = GetRestful.getSubResourceClass(componentClass);
        final String jndiName;
        if (component.getViews().size() == 1) {
          // only 1 view, just use the simple JNDI name
          jndiName =
              "java:app/" + moduleDescription.getModuleName() + "/" + component.getComponentName();
        } else {
          boolean found = false;
          String foundType = null;
          for (final ViewDescription view : component.getViews()) {
            for (Class subResource : jaxrsType) {
              if (view.getViewClassName().equals(subResource.getName())) {
                foundType = subResource.getName();
                found = true;
                break;
              }
            }
            if (found) {
              break;
            }
          }
          if (!found) {
            throw JaxrsMessages.MESSAGES.typeNameNotAnEjbView(
                Arrays.asList(jaxrsType), component.getComponentName());
          }
          jndiName =
              "java:app/"
                  + moduleDescription.getModuleName()
                  + "/"
                  + component.getComponentName()
                  + "!"
                  + foundType;
        }

        JAXRS_LOGGER.debugf(
            "Found JAX-RS Managed Bean: %s local jndi jaxRsTypeName: %s",
            component.getComponentClassName(), jndiName);
        StringBuilder buf = new StringBuilder();
        buf.append(jndiName)
            .append(";")
            .append(component.getComponentClassName())
            .append(";")
            .append("true");

        resteasy.getScannedJndiComponentResources().add(buf.toString());
        // make sure its removed from list
        resteasy.getScannedResourceClasses().remove(component.getComponentClassName());
      } else if (component instanceof ManagedBeanComponentDescription) {
        String jndiName =
            "java:app/" + moduleDescription.getModuleName() + "/" + component.getComponentName();

        JAXRS_LOGGER.debugf(
            "Found JAX-RS Managed Bean: %s local jndi name: %s",
            component.getComponentClassName(), jndiName);
        StringBuilder buf = new StringBuilder();
        buf.append(jndiName)
            .append(";")
            .append(component.getComponentClassName())
            .append(";")
            .append("true");

        resteasy.getScannedJndiComponentResources().add(buf.toString());
        // make sure its removed from list
        resteasy.getScannedResourceClasses().remove(component.getComponentClassName());
      }
    }
  }