/** {@inheritDoc} */
 public ClassSpec getClassSpec(final String name) throws IOException {
   final VirtualFile file = root.getChild(name);
   if (!file.exists()) {
     return null;
   }
   final long size = file.getSize();
   final ClassSpec spec = new ClassSpec();
   final InputStream is = file.openStream();
   try {
     if (size <= (long) Integer.MAX_VALUE) {
       final int castSize = (int) size;
       byte[] bytes = new byte[castSize];
       int a = 0, res;
       while ((res = is.read(bytes, a, castSize - a)) > 0) {
         a += res;
       }
       // done
       is.close();
       spec.setBytes(bytes);
       spec.setCodeSource(new CodeSource(rootUrl, file.getCodeSigners()));
       return spec;
     } else {
       throw ServerMessages.MESSAGES.resourceTooLarge();
     }
   } finally {
     VFSUtils.safeClose(is);
   }
 }
  public void deploy(final DeploymentPhaseContext phaseContext)
      throws DeploymentUnitProcessingException {
    final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
    if (!DeploymentTypeMarker.isType(DeploymentType.EAR, deploymentUnit)) {
      return;
    }
    final ResourceRoot deploymentRoot =
        deploymentUnit.getAttachment(org.jboss.as.server.deployment.Attachments.DEPLOYMENT_ROOT);
    final VirtualFile deploymentFile = deploymentRoot.getRoot();
    final VirtualFile applicationXmlFile = deploymentFile.getChild(JBOSS_APP_XML);
    if (!applicationXmlFile.exists()) {
      return;
    }

    InputStream inputStream = null;
    try {
      inputStream = applicationXmlFile.openStream();
      final XMLInputFactory inputFactory = XMLInputFactory.newInstance();
      inputFactory.setXMLResolver(NoopXmlResolver.create());
      XMLStreamReader xmlReader = inputFactory.createXMLStreamReader(inputStream);
      final JBossAppMetaData appMetaData = JBossAppMetaDataParser.parse(xmlReader);
      if (appMetaData != null) {
        final EarMetaData earMetaData = deploymentUnit.getAttachment(Attachments.EAR_METADATA);
        if (earMetaData != null) {
          JBossAppMetaDataMerger.merge(appMetaData, null, earMetaData);
        }
        deploymentUnit.putAttachment(Attachments.JBOSS_APP_METADATA, appMetaData);
      }
    } catch (Exception e) {
      throw new DeploymentUnitProcessingException("Failed to parse " + applicationXmlFile, e);
    } finally {
      VFSUtils.safeClose(inputStream);
    }
  }
  @Override
  public Set<String> getUpdatedResources(
      final String deploymentName, final Map<String, Long> updatedResources) {
    final ModuleIdentifier moduleId = getModuleIdentifier(deploymentName);
    final ModuleClassLoader loader = loadersByModuleIdentifier.get(moduleId);
    if (loader == null) {
      return Collections.emptySet();
    }

    final DeploymentUnit deploymentUnit =
        (DeploymentUnit)
            CurrentServiceRegistry.getServiceRegistry()
                .getRequiredService(Services.deploymentUnitName(deploymentName))
                .getValue();
    final ResourceRoot root = deploymentUnit.getAttachment(Attachments.DEPLOYMENT_ROOT);

    final Set<String> resources = new HashSet<String>();
    for (final Map.Entry<String, Long> entry : updatedResources.entrySet()) {
      final VirtualFile file = root.getRoot().getChild(entry.getKey());
      if (file.exists()) {
        long last = file.getLastModified();
        if (entry.getValue() > last) {
          resources.add(entry.getKey());
        }
      }
    }
    return resources;
  }
  /**
   * Process a deployment for jboss-service.xml files. Will parse the xml file and attach a
   * configuration discovered during processing.
   *
   * @param phaseContext the deployment unit context
   * @throws DeploymentUnitProcessingException
   */
  public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {

    final VirtualFile deploymentRoot =
        phaseContext.getDeploymentUnit().getAttachment(Attachments.DEPLOYMENT_ROOT).getRoot();

    if (deploymentRoot == null || !deploymentRoot.exists()) return;

    VirtualFile serviceXmlFile = null;
    if (deploymentRoot.isDirectory()) {
      serviceXmlFile = deploymentRoot.getChild(SERVICE_DESCRIPTOR_PATH);
    } else if (deploymentRoot
        .getName()
        .toLowerCase(Locale.ENGLISH)
        .endsWith(SERVICE_DESCRIPTOR_SUFFIX)) {
      serviceXmlFile = deploymentRoot;
    }
    if (serviceXmlFile == null || !serviceXmlFile.exists()) return;

    final XMLMapper xmlMapper = XMLMapper.Factory.create();
    final JBossServiceXmlDescriptorParser jBossServiceXmlDescriptorParser =
        new JBossServiceXmlDescriptorParser(
            JBossDescriptorPropertyReplacement.propertyReplacer(phaseContext.getDeploymentUnit()));
    xmlMapper.registerRootElement(
        new QName("urn:jboss:service:7.0", "server"), jBossServiceXmlDescriptorParser);
    xmlMapper.registerRootElement(new QName(null, "server"), jBossServiceXmlDescriptorParser);

    InputStream xmlStream = null;
    try {
      xmlStream = serviceXmlFile.openStream();
      final XMLStreamReader reader = inputFactory.createXMLStreamReader(xmlStream);
      final ParseResult<JBossServiceXmlDescriptor> result =
          new ParseResult<JBossServiceXmlDescriptor>();
      xmlMapper.parseDocument(result, reader);
      final JBossServiceXmlDescriptor xmlDescriptor = result.getResult();
      if (xmlDescriptor != null)
        phaseContext
            .getDeploymentUnit()
            .putAttachment(JBossServiceXmlDescriptor.ATTACHMENT_KEY, xmlDescriptor);
      else throw SarMessages.MESSAGES.failedXmlParsing(serviceXmlFile);
    } catch (Exception e) {
      throw SarMessages.MESSAGES.failedXmlParsing(e, serviceXmlFile);
    } finally {
      VFSUtils.safeClose(xmlStream);
    }
  }
 /** {@inheritDoc} */
 public boolean exists(VirtualFile mountPoint, VirtualFile target) {
   if (mountPoint.equals(target)) {
     return true;
   }
   final VirtualFile assemblyFile = assembly.getFile(mountPoint, target);
   if (assemblyFile != null) {
     return assemblyFile.exists();
   }
   return assembly.contains(mountPoint, target);
 }
 /** {@inheritDoc} */
 public Resource getResource(final String name) {
   try {
     final VirtualFile file = root.getChild(PathUtils.canonicalize(name));
     if (!file.exists()) {
       return null;
     }
     return new VFSEntryResource(file, file.toURL());
   } catch (MalformedURLException e) {
     // must be invalid...?  (todo: check this out)
     return null;
   }
 }
  @SuppressWarnings("unchecked")
  public void deploy(VFSDeploymentUnit unit) throws DeploymentException {
    TorqueBoxMetaData globalMetaData = unit.getAttachment(TorqueBoxMetaData.class);

    log.debug("Global torquebox.yml: " + globalMetaData);

    Object data = null;

    if (globalMetaData != null) {
      data = globalMetaData.getSection(getSectionName());
      log.debug("Global data section for " + getSectionName() + ": " + data);
    }

    if (data == null && isSupportsStandalone()) {
      VirtualFile metaDataFile = getMetaDataFile(unit, getFileName());

      if ((metaDataFile != null) && metaDataFile.exists()) {
        log.warn("Usage of " + getFileName() + " is deprecated.  Please use torquebox.yml.");
        InputStream in = null;
        try {
          in = metaDataFile.openStream();
          Yaml yaml = new Yaml();
          data = (Map<String, ?>) yaml.load(in);
        } catch (YAMLException e) {
          log.warn("Error parsing: " + metaDataFile + ": " + e.getMessage());
          data = null;
        } catch (IOException e) {
          throw new DeploymentException(e);
        } finally {
          if (in != null) {
            try {
              in.close();
            } catch (IOException e) {
              throw new DeploymentException(e);
            }
          }
        }
      }
    }

    if (data == null) {
      return;
    }

    try {
      parse(unit, data);
    } catch (DeploymentException e) {
      throw e;
    } catch (Exception e) {
      throw new DeploymentException(e);
    }
  }
 /**
  * Batch deployments must have a {@code META-INF/batch.xml} and/or XML configuration files in
  * {@code META-INF/batch-jobs}. They must be in an EJB JAR or a WAR.
  *
  * @param deploymentUnit the deployment unit to check
  * @return {@code true} if a {@code META-INF/batch.xml} or a non-empty {@code META-INF/batch-jobs}
  *     directory was found otherwise {@code false}
  */
 private boolean isBatchDeployment(final DeploymentUnit deploymentUnit) {
   // Section 10.7 of JSR 352 discusses valid packaging types, of which it appears EAR should be
   // one. It seems
   // though that it's of no real use as 10.5 and 10.6 seem to indicate it must be in
   // META-INF/batch-jobs of a JAR
   // and WEB-INF/classes/META-INF/batch-jobs of a WAR.
   if (DeploymentTypeMarker.isType(DeploymentType.EAR, deploymentUnit)
       || !deploymentUnit.hasAttachment(Attachments.DEPLOYMENT_ROOT)) {
     return false;
   }
   final ResourceRoot root = deploymentUnit.getAttachment(Attachments.DEPLOYMENT_ROOT);
   final VirtualFile metaInf;
   if (DeploymentTypeMarker.isType(DeploymentType.WAR, deploymentUnit)) {
     metaInf = root.getRoot().getChild("WEB-INF/classes/META-INF");
   } else {
     metaInf = root.getRoot().getChild("META-INF");
   }
   final VirtualFile jobXmlFile = metaInf.getChild("batch.xml");
   final VirtualFile batchJobsDir = metaInf.getChild("batch-jobs");
   return (jobXmlFile.exists()
       || (batchJobsDir.exists() && !batchJobsDir.getChildren().isEmpty()));
 }
  /**
   * Process a deployment for standard ra deployment files. Will parse the xml file and attach an
   * configuration discovered during processing.
   *
   * @param phaseContext the deployment unit context
   * @throws DeploymentUnitProcessingException
   */
  @Override
  public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
    final VirtualFile deploymentRoot =
        phaseContext.getDeploymentUnit().getAttachment(Attachments.DEPLOYMENT_ROOT).getRoot();

    if (deploymentRoot == null || !deploymentRoot.exists()) return;

    final String deploymentRootName = deploymentRoot.getLowerCaseName();
    if (!deploymentRootName.endsWith(".rar")) {
      return;
    }

    VirtualFile serviceXmlFile = deploymentRoot.getChild("/META-INF/ra.xml");

    InputStream xmlStream = null;
    Connector result = null;
    try {
      if (serviceXmlFile != null && serviceXmlFile.exists()) {

        xmlStream = serviceXmlFile.openStream();
        result = (new RaParser()).parse(xmlStream);
        if (result == null) throw MESSAGES.failedToParseServiceXml(serviceXmlFile);
      }
      File root = deploymentRoot.getPhysicalFile();
      URL url = root.toURI().toURL();
      String deploymentName = deploymentRootName.substring(0, deploymentRootName.indexOf(".rar"));
      ConnectorXmlDescriptor xmlDescriptor =
          new ConnectorXmlDescriptor(result, root, url, deploymentName);
      phaseContext
          .getDeploymentUnit()
          .putAttachment(ConnectorXmlDescriptor.ATTACHMENT_KEY, xmlDescriptor);

    } catch (Exception e) {
      throw MESSAGES.failedToParseServiceXml(e, serviceXmlFile);
    } finally {
      VFSUtils.safeClose(xmlStream);
    }
  }
  @Test
  public void testLoadCorrectJbossWeb() throws Exception {
    final VirtualFile jbossWebxml = mock(VirtualFile.class);
    when(jbossWebxml.exists()).thenReturn(Boolean.TRUE);
    when(jbossWebxml.openStream())
        .thenReturn(
            JBossWebParsingDeploymentProcessorTest.class.getResourceAsStream("jboss-web.xml"));

    final VirtualFile deploymentRoot = mock(VirtualFile.class);
    when(deploymentRoot.getChild("WEB-INF/jboss-web.xml")).thenReturn(jbossWebxml);

    final ResourceRoot resourceRoot = mock(ResourceRoot.class);
    when(resourceRoot.getRoot()).thenReturn(deploymentRoot);
    when(deploymentUnit.getAttachment(org.jboss.as.server.deployment.Attachments.DEPLOYMENT_ROOT))
        .thenReturn(resourceRoot);
    processor.deploy(phaseContext);
  }
  /** {@inheritDoc} */
  public Collection<String> getPaths() {
    final List<String> index = new ArrayList<String>();
    // First check for an index file
    final VirtualFile indexFile = VFS.getChild(root.getPathName() + ".index");
    if (indexFile.exists()) {
      try {
        final BufferedReader r = new BufferedReader(new InputStreamReader(indexFile.openStream()));
        try {
          String s;
          while ((s = r.readLine()) != null) {
            index.add(s.trim());
          }
          return index;
        } finally {
          // if exception is thrown, undo index creation
          r.close();
        }
      } catch (IOException e) {
        index.clear();
      }
    }

    FilterVirtualFileVisitor visitor =
        new FilterVirtualFileVisitor(
            new VirtualFileFilter() {
              @Override
              public boolean accepts(VirtualFile file) {
                return file.isDirectory();
              }
            },
            VisitorAttributes.RECURSE);
    try {
      root.visit(visitor);
    } catch (IOException e) {
      index.clear();
    }

    index.add("");
    for (VirtualFile dir : visitor.getMatched()) {
      index.add(dir.getPathNameRelativeTo(root));
    }

    return index;
  }
  @Override
  public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {

    // Check if we already have an OSGi deployment
    DeploymentUnit depUnit = phaseContext.getDeploymentUnit();
    if (depUnit.hasAttachment(OSGiConstants.OSGI_METADATA_KEY)) return;

    // Get the OSGi XService properties
    VirtualFile virtualFile = depUnit.getAttachment(Attachments.DEPLOYMENT_ROOT).getRoot();
    VirtualFile xserviceFile = virtualFile.getChild(XSERVICE_PROPERTIES_NAME);
    if (xserviceFile.exists() == false) return;

    try {
      Properties props = new Properties();
      props.load(xserviceFile.openStream());
      OSGiMetaData metadata = OSGiMetaDataBuilder.load(props);
      depUnit.putAttachment(OSGiConstants.OSGI_METADATA_KEY, metadata);
    } catch (IOException ex) {
      throw MESSAGES.cannotParseOSGiMetadata(ex, xserviceFile);
    }
  }
  public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
    final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
    final ResourceRoot resourceRoot = deploymentUnit.getAttachment(Attachments.DEPLOYMENT_ROOT);
    if (resourceRoot == null) {
      return;
    }
    final VirtualFile deploymentRoot = resourceRoot.getRoot();
    if (deploymentRoot == null || !deploymentRoot.exists()) {
      return;
    }

    final String deploymentRootName = deploymentRoot.getLowerCaseName();
    if (!deploymentRootName.endsWith(RAR_EXTENSION)) {
      return;
    }
    // we do not load classes from the module resource root
    ModuleRootMarker.mark(resourceRoot, false);

    try {
      final List<VirtualFile> childArchives = deploymentRoot.getChildren(CHILD_ARCHIVE_FILTER);

      for (final VirtualFile child : childArchives) {
        final Closeable closable =
            child.isFile()
                ? VFS.mountZip(child, child, TempFileProviderService.provider())
                : NO_OP_CLOSEABLE;
        final MountHandle mountHandle = new MountHandle(closable);
        final ResourceRoot childResource = new ResourceRoot(child, mountHandle);
        ModuleRootMarker.mark(childResource);
        deploymentUnit.addToAttachmentList(Attachments.RESOURCE_ROOTS, childResource);
        resourceRoot.addToAttachmentList(
            Attachments.INDEX_IGNORE_PATHS, child.getPathNameRelativeTo(deploymentRoot));
      }
    } catch (IOException e) {
      throw new DeploymentUnitProcessingException(
          "Failed to process RA child archives for [" + deploymentRoot + "]", e);
    }
  }
  @Test
  public void testLoadIncorrectJbossWeb() throws Exception {
    expectedException.expect(DeploymentUnitProcessingException.class);
    expectedException.expectMessage(
        "JBAS018014: Failed to parse XML descriptor \"/content/basic.war/WEB-INF/jboss-web.xml\" at [4,5]");

    final VirtualFile jbossWebxml = mock(VirtualFile.class);
    when(jbossWebxml.exists()).thenReturn(Boolean.TRUE);
    when(jbossWebxml.openStream())
        .thenReturn(
            JBossWebParsingDeploymentProcessorTest.class.getResourceAsStream(
                "jboss-error-web.xml"));
    when(jbossWebxml.toString()).thenReturn("\"/content/basic.war/WEB-INF/jboss-web.xml\"");

    final VirtualFile deploymentRoot = mock(VirtualFile.class);
    when(deploymentRoot.getChild("WEB-INF/jboss-web.xml")).thenReturn(jbossWebxml);

    final ResourceRoot resourceRoot = mock(ResourceRoot.class);
    when(resourceRoot.getRoot()).thenReturn(deploymentRoot);
    when(deploymentUnit.getAttachment(org.jboss.as.server.deployment.Attachments.DEPLOYMENT_ROOT))
        .thenReturn(resourceRoot);
    processor.deploy(phaseContext);
  }
  /**
   * We only allow a single deployment at a time to be run through the class path processor.
   *
   * <p>This is because if multiple sibling deployments reference the same item we need to make sure
   * that they end up with the same external module, and do not both create an external module with
   * the same name.
   */
  public synchronized void deploy(final DeploymentPhaseContext phaseContext)
      throws DeploymentUnitProcessingException {
    final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();

    final DeploymentUnit parent = deploymentUnit.getParent();
    final DeploymentUnit topLevelDeployment = parent == null ? deploymentUnit : parent;
    final VirtualFile topLevelRoot =
        topLevelDeployment.getAttachment(Attachments.DEPLOYMENT_ROOT).getRoot();
    final ExternalModuleService externalModuleService =
        topLevelDeployment.getAttachment(Attachments.EXTERNAL_MODULE_SERVICE);
    final ResourceRoot deploymentRoot = deploymentUnit.getAttachment(Attachments.DEPLOYMENT_ROOT);

    // These are resource roots that are already accessible by default
    // such as ear/lib jars an web-inf/lib jars
    final Set<VirtualFile> existingAccessibleRoots = new HashSet<VirtualFile>();

    final Map<VirtualFile, ResourceRoot> subDeployments = new HashMap<VirtualFile, ResourceRoot>();
    for (ResourceRoot root : DeploymentUtils.allResourceRoots(topLevelDeployment)) {
      if (SubDeploymentMarker.isSubDeployment(root)) {
        subDeployments.put(root.getRoot(), root);
      } else if (ModuleRootMarker.isModuleRoot(root)) {
        // top level module roots are already accessible, as they are either
        // ear/lib jars, or jars that are already part of the deployment
        existingAccessibleRoots.add(root.getRoot());
      }
    }

    final ArrayDeque<RootEntry> resourceRoots = new ArrayDeque<RootEntry>();
    if (deploymentUnit.getParent() != null) {
      // top level deployments already had their exiting roots processed above
      for (ResourceRoot root : DeploymentUtils.allResourceRoots(deploymentUnit)) {

        if (ModuleRootMarker.isModuleRoot(root)) {
          // if this is a sub deployment of an ear we need to make sure we don't
          // re-add existing module roots as class path entries
          // this will mainly be WEB-INF/(lib|classes) entries
          existingAccessibleRoots.add(root.getRoot());
        }
      }
    }

    for (ResourceRoot root : DeploymentUtils.allResourceRoots(deploymentUnit)) {
      // add this to the list of roots to be processed
      resourceRoots.add(new RootEntry(deploymentUnit, root));
    }

    // build a map of the additional module locations
    // note that if a resource root has been added to two different additional modules
    // and is then referenced via a Class-Path entry the behaviour is undefined
    final Map<VirtualFile, AdditionalModuleSpecification> additionalModules =
        new HashMap<VirtualFile, AdditionalModuleSpecification>();
    for (AdditionalModuleSpecification module :
        topLevelDeployment.getAttachmentList(Attachments.ADDITIONAL_MODULES)) {
      for (ResourceRoot additionalModuleResourceRoot : module.getResourceRoots()) {
        additionalModules.put(additionalModuleResourceRoot.getRoot(), module);
      }
    }

    // additional resource roots may be added as
    while (!resourceRoots.isEmpty()) {
      final RootEntry entry = resourceRoots.pop();
      final ResourceRoot resourceRoot = entry.resourceRoot;
      final Attachable target = entry.target;

      // if this is a top level deployment we do not want to process sub deployments
      if (SubDeploymentMarker.isSubDeployment(resourceRoot) && resourceRoot != deploymentRoot) {
        continue;
      }

      final String[] items = getClassPathEntries(resourceRoot);
      for (final String item : items) {
        if (item.isEmpty()) {
          continue;
        }
        // first try and resolve relative to the manifest resource root
        final VirtualFile classPathFile = resourceRoot.getRoot().getParent().getChild(item);
        // then resolve relative to the deployment root
        final VirtualFile topLevelClassPathFile =
            deploymentRoot.getRoot().getParent().getChild(item);
        if (item.startsWith("/")) {
          if (externalModuleService.isValid(item)) {
            final ModuleIdentifier moduleIdentifier = externalModuleService.addExternalModule(item);
            target.addToAttachmentList(Attachments.CLASS_PATH_ENTRIES, moduleIdentifier);
            ServerLogger.DEPLOYMENT_LOGGER.debugf(
                "Resource %s added as external jar %s", classPathFile, resourceRoot.getRoot());
          } else {
            ServerLogger.DEPLOYMENT_LOGGER.classPathEntryNotValid(
                item, resourceRoot.getRoot().getPathName());
          }
        } else {
          if (classPathFile.exists()) {
            // we need to check that this class path item actually lies within the deployment
            boolean found = false;
            VirtualFile file = classPathFile.getParent();
            while (file != null) {
              if (file.equals(topLevelRoot)) {
                found = true;
              }
              file = file.getParent();
            }
            if (!found) {
              ServerLogger.DEPLOYMENT_LOGGER.classPathEntryNotValid(
                  item, resourceRoot.getRoot().getPathName());
            } else {
              handlingExistingClassPathEntry(
                  deploymentUnit,
                  resourceRoots,
                  topLevelDeployment,
                  topLevelRoot,
                  subDeployments,
                  additionalModules,
                  existingAccessibleRoots,
                  resourceRoot,
                  target,
                  classPathFile);
            }
          } else if (topLevelClassPathFile.exists()) {
            boolean found = false;
            VirtualFile file = topLevelClassPathFile.getParent();
            while (file != null) {
              if (file.equals(topLevelRoot)) {
                found = true;
              }
              file = file.getParent();
            }
            if (!found) {
              ServerLogger.DEPLOYMENT_LOGGER.classPathEntryNotValid(
                  item, resourceRoot.getRoot().getPathName());
            } else {
              handlingExistingClassPathEntry(
                  deploymentUnit,
                  resourceRoots,
                  topLevelDeployment,
                  topLevelRoot,
                  subDeployments,
                  additionalModules,
                  existingAccessibleRoots,
                  resourceRoot,
                  target,
                  topLevelClassPathFile);
            }
          } else {
            ServerLogger.DEPLOYMENT_LOGGER.classPathEntryNotValid(
                item, resourceRoot.getRoot().getPathName());
          }
        }
      }
    }
  }
  /** {@inheritDoc} */
  public void deploy(final DeploymentPhaseContext phaseContext)
      throws DeploymentUnitProcessingException {
    final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
    final List<ResourceRoot> resourceRoots = DeploymentUtils.allResourceRoots(deploymentUnit);

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

    final DeploymentUnit parent = deploymentUnit.getParent();
    final DeploymentUnit topLevelDeployment = parent == null ? deploymentUnit : parent;
    final VirtualFile toplevelRoot =
        topLevelDeployment.getAttachment(Attachments.DEPLOYMENT_ROOT).getRoot();
    final ExternalModuleService externalModuleService =
        topLevelDeployment.getAttachment(Attachments.EXTERNAL_MODULE_SERVICE);

    final Map<VirtualFile, ResourceRoot> files = new HashMap<VirtualFile, ResourceRoot>();
    for (ResourceRoot resourceRoot : resourceRoots) {
      files.put(resourceRoot.getRoot(), resourceRoot);
    }
    final Deque<ResourceRoot> libResourceRoots = new ArrayDeque<ResourceRoot>();
    // scan /lib entries for class-path items
    for (ResourceRoot resourceRoot : resourceRoots) {
      if (ModuleRootMarker.isModuleRoot(resourceRoot)
          && !SubDeploymentMarker.isSubDeployment(resourceRoot)) {
        libResourceRoots.add(resourceRoot);
      }
    }
    while (!libResourceRoots.isEmpty()) {
      final ResourceRoot resourceRoot = libResourceRoots.pop();
      final String[] items = getClassPathEntries(resourceRoot);
      for (String item : items) {
        final VirtualFile classPathFile = resourceRoot.getRoot().getParent().getChild(item);
        if (!classPathFile.exists()) {
          log.warnf("Class Path entry %s in %s not found. ", item, resourceRoot.getRoot());
        } else if (isInside(classPathFile, toplevelRoot)) {
          if (!files.containsKey(classPathFile)) {
            log.warnf(
                "Class Path entry %s in %s does not point to a valid jar for a Class-Path reference.",
                item, resourceRoot.getRoot());
          } else {
            final ResourceRoot target = files.get(classPathFile);
            if (SubDeploymentMarker.isSubDeployment(target)) {
              // for now we do not allow ear Class-Path references to subdeployments
              log.warnf(
                  "Class Path entry  in "
                      + resourceRoot.getRoot()
                      + "  may not point to a sub deployment.");
            } else if (!ModuleRootMarker.isModuleRoot(target)) {
              // otherwise just add it to the lib dir
              ModuleRootMarker.mark(target);
              libResourceRoots.push(target);
              log.debugf(
                  "Resource %s added to logical lib directory due to Class-Path entry in %s",
                  classPathFile, target.getRoot());
            }
            // otherwise it is already part of lib, so we leave it alone for now
          }
        } else if (item.startsWith("/")) {
          ModuleIdentifier moduleIdentifier = externalModuleService.addExternalModule(item);
          deploymentUnit.addToAttachmentList(Attachments.CLASS_PATH_ENTRIES, moduleIdentifier);
          log.debugf("Resource %s added as external jar %s", classPathFile, resourceRoot.getRoot());
        } else {
          // this is a dep on another deployment
          deploymentUnit.addToAttachmentList(
              Attachments.CLASS_PATH_ENTRIES,
              ModuleIdentifier.create(ServiceModuleLoader.MODULE_PREFIX + classPathFile.getName()));
        }
      }
    }
  }
  @Override
  public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
    final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
    if (!DeploymentTypeMarker.isType(DeploymentType.WAR, deploymentUnit)) {
      return; // Skip non web deployments
    }
    final ResourceRoot deploymentRoot = deploymentUnit.getAttachment(Attachments.DEPLOYMENT_ROOT);
    final VirtualFile alternateDescriptor =
        deploymentRoot.getAttachment(
            org.jboss.as.ee.structure.Attachments.ALTERNATE_WEB_DEPLOYMENT_DESCRIPTOR);
    // Locate the descriptor
    final VirtualFile webXml;
    if (alternateDescriptor != null) {
      webXml = alternateDescriptor;
    } else {
      webXml = deploymentRoot.getRoot().getChild(WEB_XML);
    }
    final WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
    assert warMetaData != null;
    if (webXml.exists()) {
      InputStream is = null;
      try {
        is = webXml.openStream();
        final XMLInputFactory inputFactory = XMLInputFactory.newInstance();

        MetaDataElementParser.DTDInfo dtdInfo = new MetaDataElementParser.DTDInfo();
        inputFactory.setXMLResolver(dtdInfo);
        final XMLStreamReader xmlReader = inputFactory.createXMLStreamReader(is);

        WebMetaData webMetaData =
            WebMetaDataParser.parse(
                xmlReader,
                dtdInfo,
                SpecDescriptorPropertyReplacement.propertyReplacer(deploymentUnit));

        if (schemaValidation && webMetaData.getSchemaLocation() != null) {
          XMLSchemaValidator validator = new XMLSchemaValidator(new XMLResourceResolver());
          InputStream xmlInput = webXml.openStream();
          try {
            if (webMetaData.is23())
              validator.validate(
                  "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN", xmlInput);
            else if (webMetaData.is24())
              validator.validate("http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd", xmlInput);
            else if (webMetaData.is25())
              validator.validate("http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd", xmlInput);
            else if (webMetaData.is30())
              validator.validate("http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd", xmlInput);
            else if (webMetaData.is31())
              validator.validate("http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd", xmlInput);
            else
              validator.validate(
                  "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN", xmlInput);
          } catch (SAXException e) {
            throw new DeploymentUnitProcessingException("Failed to validate " + webXml, e);
          } finally {
            xmlInput.close();
          }
        }
        warMetaData.setWebMetaData(webMetaData);

      } catch (XMLStreamException e) {
        throw new DeploymentUnitProcessingException(
            MESSAGES.failToParseXMLDescriptor(
                webXml, e.getLocation().getLineNumber(), e.getLocation().getColumnNumber()));
      } catch (IOException e) {
        throw new DeploymentUnitProcessingException(MESSAGES.failToParseXMLDescriptor(webXml), e);
      } finally {
        try {
          if (is != null) {
            is.close();
          }
        } catch (IOException e) {
          // Ignore
        }
      }
    }
  }
  /**
   * Finds a ejb-jar.xml (at WEB-INF of a .war or META-INF of a .jar) parses the file and creates
   * metadata out of it. The metadata is then attached to the deployment unit.
   *
   * @param deploymentPhase
   * @throws DeploymentUnitProcessingException
   */
  @Override
  public void deploy(DeploymentPhaseContext deploymentPhase)
      throws DeploymentUnitProcessingException {

    // get hold of the deployment unit.
    DeploymentUnit deploymentUnit = deploymentPhase.getDeploymentUnit();

    // get the root of the deployment unit
    VirtualFile deploymentRoot =
        deploymentUnit.getAttachment(Attachments.DEPLOYMENT_ROOT).getRoot();

    // Locate a ejb-jar.xml
    VirtualFile ejbJarXml = null;
    // EJB 3.1 FR 20.4 Enterprise Beans Packaged in a .war
    // TODO: Is there a better way to do this?
    if (deploymentRoot.getName().toLowerCase().endsWith(WAR_FILE_EXTENSION)) {
      // it's a .war file, so look for the ejb-jar.xml in WEB-INF
      ejbJarXml = deploymentRoot.getChild(EJB_JAR_XML_LOCATION_IN_WAR);
    } else if (deploymentRoot.getName().toLowerCase().endsWith(JAR_FILE_EXTENSION)) {
      ejbJarXml = deploymentRoot.getChild(EJB_JAR_XML_LOCATION_IN_JAR);
    } else {
      // neither a .jar nor a .war. Return
      return;
    }

    if (ejbJarXml == null || !ejbJarXml.exists()) {
      // no ejb-jar.xml found, nothing to do!
      return;
    }
    // Mark it as a EJB deployment
    EjbDeploymentMarker.mark(deploymentUnit);
    if (!deploymentUnit.hasAttachment(EjbDeploymentAttachmentKeys.EJB_JAR_DESCRIPTION)) {
      final EEModuleDescription moduleDescription =
          deploymentUnit.getAttachment(org.jboss.as.ee.component.Attachments.EE_MODULE_DESCRIPTION);
      final EjbJarDescription ejbModuleDescription = new EjbJarDescription(moduleDescription);
      deploymentUnit.putAttachment(
          EjbDeploymentAttachmentKeys.EJB_JAR_DESCRIPTION, ejbModuleDescription);
    }

    // get the XMLStreamReader and parse the ejb-jar.xml
    MetaDataElementParser.DTDInfo dtdInfo = new MetaDataElementParser.DTDInfo();
    InputStream stream = null;
    try {
      stream = ejbJarXml.openStream();

      XMLStreamReader reader = this.getXMLStreamReader(stream, ejbJarXml, dtdInfo);

      EjbJarMetaData ejbJarMetaData = EjbJarMetaDataParser.parse(reader, dtdInfo);
      // attach the EjbJarMetaData to the deployment unit
      deploymentUnit.putAttachment(EjbDeploymentAttachmentKeys.EJB_JAR_METADATA, ejbJarMetaData);

    } catch (XMLStreamException xmlse) {
      throw new DeploymentUnitProcessingException(
          "Exception while parsing ejb-jar.xml: " + ejbJarXml.getPathName(), xmlse);
    } catch (IOException ioe) {
      throw new DeploymentUnitProcessingException(
          "Failed to create reader for ejb-jar.xml: " + ejbJarXml.getPathName(), ioe);
    } finally {
      try {
        if (stream != null) {
          stream.close();
        }
      } catch (IOException ioe) {
        logger.debug("Ignoring exception while closing the InputStream ", ioe);
      }
    }
  }